Ruby on Ranting

Update: It seems this rant got around on the ruby-talk mailing list. I’d just like everyone to keep in mind that I wrote this when I was first introduced to the language, and I wrote it for myself and myself only. I enjoy writing to collect my thoughts, which is the only reason my Website exists. It’s in a public forum because my friends enjoy reading them, and I enjoy combining writing and technology (ie, a Website). If you’re offended, well, too bad, I guess. I’m an opinionated jerk, and I never claimed this was objective. The entire point of this rant was to debunk the so-called “POLS,” which, according to the many, many emails I’ve received, isn’t taken seriously and should be ignored. So, by that point, this rant is just a list of things that irritate me about the language, as would be found in any language. If you don’t like my “presentation” style (satire, humor, swearing), then don’t read it. I meant no ill-will toward matz, whom I highly respect. I have a habit of complaining about anything and everything, it’s what I do. If you were raised in my family, you would, too. Oh, and, about the swearing, so what? I don’t know what imaginary land you’re all living in, but in St. Louis, people swear. Also, keep in mind that most of your emails were just as brutal as my rant. :) For a more detailed response, see here.

This rant is meant to go hand-in-hand with my Python rant.

I think Ruby is a really cool language, but I think it’s far too hyped. People love it because it’s different. Yeah, that’s why I hate it. It’s different in stupid ways that we figured out were stupid back with Smalltalk and Eiffel. There’s a reason no one uses them. I mean, sure, yanking the yield keyword from a neat language like CLU might make you think that that means something, but it doesn’t. It means they yanked the yield keyword from CLU. That’s it. Python did it too.

Ruby claims to follow the “Principle of Least Surprise.” I, for one, think that this is absolute bullshit and it fails utterly and completely at this claim. These are my reasons.

I discovered these things as I worked with Ruby in late 2004. Some of them from coding, and some of them from just reading the Pickaxe2. Some of these items may have been fixed or had solutions that I wasn’t aware of (even though I did Google most of these to see if there were any reasonable popular solutions). Bear with me.

It’s 5.abs for absolute value, but Math.sqrt(5) for square root.

Almost every Ruby document I read boasts about how everything’s a method and how it’s a “pure OO” language. Whoops. I guess not.

So much for POLS.

Only nil and false evaluate to false.

That is to say, empty sets like [], {}, and "" all evaluate to true. But here’s the kicker: 0 also evaluates to true:

if 0     # True
if []    # True
if {}    # True
if ""    # True
if nil   # False
if false # False

In all fairness, I see the logic behind it. After all, 0 is an instance of Fixnum, so it is something. An empty array is still an array, so it’s still something. One must result to using the empty? method instead of boolean shortcuts. This isn’t so much a Bad Thing, really.

But when I do if 0 I damn well expect it to be false.

So much for POLS.

There’s no decent namespace mechanism a la Python.

I mean, shit, even Perl beats Ruby here (package).

Ruby gets half a point for at least providing a halfassed module directive that creates namespaces as a side-effect. You have to rely on the kindness of library authors to properly do this, and most don’t, because modules are really a form of cheesy multiple-inheritance. Also, it’s an utter pain in the ass to wrap your everything inside a module block.

There’s also no way to emulate this that I can find:

Is something akin to Python’s import, where namespaces are implicitly created based on file pathes and names, too much to ask?

I expect implicit namespaces after working with decent scripting languages.

So much for POLS.

The self irony.

This is hilarious.

Rubyists will be the first to tell you they don’t like Python because of the explicit self everywhere. I’m just going to ignore for a moment that @attribute is no less distracting or retarded than self.attribute. In fact, I find the latter to be far more OO.

Rubyists will tell you that Python needs it because of the hacky nature of its OO, which is, in part, true. However, most Pythonistas will tell you it’s nice to have to explicitly reference things in your class, otherwise you get not only the class methods and such in the “global” namespace, but also all the shit that was there from Object and Kernel anyway.

So anyway, back to what I was bitching about. In Ruby, to declare a class method (eg, a static method in C++/Java), you do:

class SomeClass
    def SomeClass.some_method
        # This is a class method.
    end

    def some_method_1
        # This is an instance method.
    end

    def self.some_method_2
        # This is also a class method.
    end
end

So, you either explicitly append the class name or you explicitly use self. Okay, so that’s not a big deal, but imagine having to do this when it comes time to wrap your library in a module block so that namespace clashes don’t happen (eg not as a Mixin):

module SomeLib
    def SomeLib.some_method
        # This will work.
    end

    def some_method_1
        # This will seemingly disappear if imported
        # via `require` (it becomes a private instance
        # method, and you can't create an instance of a
        # module).
    end

    def self.some_method_2
        # This will also work.
    end
end

Naturally, if you use include this isn’t a problem (as for Mixins), but let’s assume in our case we want the module tag strictly for namespace purposes. What a pain in the ass, I hear you scream. However, there are a few interesting ways to get around this. The first is the most obvious (which is to say, it’d have to come up to you and hit you across the face with a 2x4 for you to think of it):

module SomeLib
    def some_method
        # Hold on to your panties.
    end

    def some_method_1
        # Or your boxers.
    end

    def some_method_2
        # Or your thong.
    end

    module_function :some_method, :some_method_1, :some_method_2
end

This has hidden implications though. This actaully creates copies of all the methods (why this is named module_function is beyond me, so much for POLS) and makes the copies class methods and makes the originals private instance methods. This is overhead that we don’t need for a namespace (since we’ll never be using those private instance methods that are hanging around).

The second way of doing this is slightly less obvious (which is to say, it’d have to come up to you and bludgeon your face against the wall for you to think of it):

module SomeLib
    extend self # Black magic.

    def some_method
        # This will work.
    end

    # ...
end

The extend method is a method of Object (and thus all objects) and is described like this:

extendobj.extend( [ mod ]+ ) -> obj

Adds to obj the instance methods from each module given as a parameter.
See also Module#extend_object.

— from “Programming Ruby” by Dave Thomas

That is to say (if this were valid syntax for both classes and modules, which it isn’t):

module SomeLib
end

module SomeLib << SomeLib
    # ...
end

Which was actually my first thought, but that doesn’t work (syntax error).

This is the method I’d use; however, as I’ve noted it’s almost impossible to decern what the hell is going on unless you look up extend and sit and stare at it for about five minutes.

So much for POLS.

Sigils are for the brain dead.

Remember back when I said “I’m just going to ignore for a moment that @attribute is no less distracting or retarded than self.attribute”? Well, here’s where I stop ignoring it.

I hate sigils (the idea of prefixing variable names with a character that denotes something special about the variable). Perl uses these extensively, and PHP uses them quite a bit as well. Unlike in Perl, however, Ruby’s sigils denote scope, not type. For some reason, @attribute in a class is supposed to be more straight-forward than self.attribute. I don’t get it really, which is why I think it’s stupid. The @@attribute form is dumb too, as you could just do a la C++ and use Class::attribute since Ruby already has the stupid :: operator hanging around anyway.

I’d expect having to reference self for this, not some retarded sigilathon.

So much or POLS.

The difference between :: and . is arbitrary and stupid.

Seriously. They use :: to access constants and . to access everything else. Why? Well, I have my ideas.

Ruby is stupid. It allows you to leave off parentheses around method calls, which is fine. Unfortunately, this makes it so that Ruby has to do a royal fuckload of processing in order to figure out if somevar is a reference to a local variable or a method call. To do this, it basically keeps a list of things that have been assigned to in the past, and considers these variables, otherwise it’s considered a method call. Sometimes it’s just plain wrong, and you get stupid errors. Just to allow some Perl hacker to leave off parentheses is not a net gain.

So what do they do? They throw another operator (::) in which does absolutely nothing different. I figured maybe they’d eliminate making method calls with :: to make the heuristic testing easier, but no, because Kernel::exit works just as well as Kernel.exit.

The difference still completely eludes me. It seems entirely arbitrary.

So much for POLS.

The ever helpful “syntax error.”

If you forget an end somewhere the only error you get is “file.rb:5: syntax error.” Well golly, thanks for that in-depth error message. It took me ten minutes to figure out what the fuck it was talking about the first time around, as the line number it spits out can be anywhere from one to infinity lines within the actual error.

At least with Python you get an “indentation error” and a line number you can actually use.

Fucking morons.

So much for POLS.

Globals that resemble the Sunday comic swear characters suck.

That is to say, the Perl special variables like $_, $*, $' et al. Fortunately, the Ruby community pretty much hates these too, and they’re steadily losing popularity in Ruby code. Ruby never should have started off with the implicit $_ shit that Perl pulls though. The only Good Thing they got from Perl was inline regular expressions.

These variables aren’t going to be familiar except to Perl hackers.

So much for POLS.

rescue without an exception catches SystemError.

That is to say:

begin
    # Some code that raises an exception.
rescue => e
    # Some code to deal with any exception.
end

Won’t work, because that’ll only catch SystemError exceptions by default. I would expect this to catch all exceptions, but to do that you have to do:

begin
    # Some code that raises an exception.
rescue Exception => e
    # Some code to deal with any exception.
end

Which is definitely kludgy. Why they did this is beyond me.

So much for POLS.

You can’t tell what raises what.

You might expect File methods to raise IOError, but no, they raise some platform-dependent shit in Errno. And since there’s absolutely no documentation that mentions what methods can raise what errors you’re usually left with rescue Exception blocks, and that’s a very Bad Thing.

You can’t even expect anything here.

So much for POLS.

Mixins are retarded.

They’re just some hacky copout for multiple-inheritence. If you leave instance methods around in module blocks you can include them in other modules and classes, thus importing their methods as instance methods into other modules and classes.

And what’s it do if there are name clashes? The same fucking thing Python’s multiple-inheritance does: searches through them in the order they were included. Why not just do real multiple-inheritence like Python?

What a giant hack.

So much for POLS.

Half the socket routines return bullshit.

What’s the deal with half of the socket routines returning port, host while the rest return a binary string that represents a struct sockaddr_in. Half the time you get usable results the other half you have to call bullshit unpacker methods on the string to get usable results.

What were these retards thinking?

So much for POLS.

The threading model is about as useful as slamming your dick in a vise.

I’m serious, it’s completely, and utterly fucking useless.

The Ruby interpreter doesn’t use native threads. This means that it effectively negates any benefits of actually using threads. It uses its own internal code scheduling to emulate threads. This means that it doesn’t actually thread, which means that you can’t do blocking calls like you normally would because you block the interpreter which effectively blocks your entire program, including all running threads (which suddenly stop running).

There’s some ADNS library (resolv and resolv-replace) that implements nonblocking DNS queries, but what about everything else? There’s a metric shitload of blocking methods in the socket library and file library.

Why did they do this? Just so they could emulate threads on MSDOS or something? What’s the point of even having threads if you can’t accomplish multiplexing? What’s the point of implementing threading if you can’t even come close to the benefits of native threads? I would at least expect native thread support on systems that support it, and if they don’t, only then use the emulation shit.

I tend to expect threading to allow for multiplexing. After all, that is the entire fucking point.

So much for POLS.

It’s tied way too closely to ASCII.

Subscripting a string returns the ASCII character code, as does iterating over a string with each.

Yeah, I’m sure anyone has ever expected that.

So much for POLS.


0 TrackBacks

Listed below are links to blogs that reference this entry.

TrackBack URL for this entry: http://mt.ericw.org/mt-tb.cgi/284


Leave a comment


Name:
Email:
URL:   
Remember personal info?