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:
You can’t do this by wrapping the
requireinside amoduleblock becauserequireis stupid and just dumps it all in your global namespace anyway.You can’t do this by wrapping a
loadinside amoduleblock because it doesn’t work with DSOs, which brings me to…You can’t do this with
SomeMod = Module.new { load 'somelib' }becauseloadcan’t do DSOs, butrequirecan, butrequireis stupid.
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:
extend — obj.extend( [ mod ]+ ) -> obj
Adds to obj the instance methods from each module given as a parameter.
See alsoModule#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
