Railing on Ruby

In my spare time (which is plentiful), I’ve been teaching myself Rails, the full-stack Ruby framework, with which I’ll build my next side project.  Side project side note: I have a big ol’ database diagram written in whiteboard marker on my window.  I feel like a real engineer!

IMG_1188
OK honestly not that big. Also? Pretty hard to read.

Anyway, Rails has some really cool features (I love the scaffolding concept, the rigorous MVC emphasis, etc.), and learning it has actually given me a bit of perspective on where other full-stack frameworks — principally Meteor, on which I built Squeaky Wheel — are coming from.  To some extent, they need to emulate Rails, because Rails has been the backbone of web app development basically since it was released 10 years ago, and a huge chunk of their primary user base is going to be coming from the Rails paradigm.  But they also emulate it because it’s convenient and it works, so while they may aim to improve upon it, they’re still using many of its key features.  I’m still learning Rails, so I have a lot of features still to learn about, but so far it seems much better than what came before it — whatever that was.

Dinos
Paleontologists now believe frameworkless PHP was invented sometime during the Triassic age and may have been a chief predator of Plateosaurus

Of course, as part of learning Rails, I’m learning a bit of Ruby.  Ruby has some cool features too, I guess?  But mostly, I kinda hate it?

My biggest problem with it is that it adds in a ton of “features” that are supposed to be convenient, but in reality just lead to sloppy code and hard-to-find bugs.  If you’re familiar with arguments in this vein, right now you’re thinking “Oh he just hates dynamic typing.” I’m not talking about static vs. dynamic typing.  (Sidenote: I believe static typing can lead to compile time errors that could have a 0% chance of being hit at runtime (although why is that code branch there, then?) — I learned on PHP and am all for dynamic typing.  Except I think you should rigorously define the output type; it drives me nuts when a function might return, for instance, an array … unless there’s only one element, then it returns that element … or false for zero elements.  THAT IS TERRIBLE PRACTICE PEOPLE WHAT ARE YOU DOING YOU ARE THE WORST.  A lot of R stuff is particularly bad (why does simplify always default to TRUE?))

I am talking very specifically about needless — and often counterintuitive or conditional — elimination of what many people would view as “cruft” — stuff like brackets, parentheses, semicolons, etc.  I like these things for the same reason that I love the Oxford comma*: it adds clarity for humans.**  Ruby has do and end to mark the beginnings and ends of blocks, but I hate anything that doesn’t specifically require brackets even for simple, one-line if statements.  Failure to provide brackets is responsible for a famous Apple SSL bug, which was written like so (with a duplicate goto fail line):

if (...) 
  goto fail;
  goto fail;

This would have been picked up immediately with curly braces and literally any text editor with auto-formatting  (or eliminated entirely):

if (...) { 
  goto fail; 
}

goto fail; # pretty obvious...

or even…

if (...) { 
 goto fail;
 goto fail;
} # completely harmless

The error comes from ambiguity in how curly brackets work: they denote a block, but aren’t necessary if the block is only one line so then they can be omitted.  Needing to remember that there is an exception (“I can omit these brackets in this case“) when it actually provides negligible benefit (honestly, two less characters matters that much to you?) opens you up to a world of hurt.  Any time you encounter a feature that includes the words “except” or “if,” you don’t have a feature, you have a potential bug.

Louie the Lightning Bug
In this case, an electrical potential bug

Ruby is positively riddled with this sort of “convenient” shortcut.  You can eliminate parentheses around function arguments unless you need to chain something (oh and by the way, this makes it really unclear whether you’re working with a function or a value, since either of the following is syntactically valid and may be hidden behind the scenes:

rand_no = 7
def rand_no  
  # do like 30 minutes of computations for no apparent reason
  7
end

And then you innocently call a = rand_no + 1 and it takes half an hour for some reason… or worse, you define both, and all of a sudden one of them needs parentheses:

rand_no = 7
def rand_no 
  8
end
rand_no
=> 7
rand_no()
=> 8

).  What if I want to use a function return value as an argument to another function? Better use parentheses because this is ambiguous:

def foo(a, b=0)   
  a + b
end
def bar(a=0, b=0)
  a - b
end

foo bar 3, 3 # does this do foo(bar(3), 3) or foo(bar(3, 3)) or ...what... -- actually it returns an error because it's ambiguous.

You see those function definitions above?  They didn’t require a return statement — so convenient.  Except that if you want to terminate execution, you can use a return statement.  There’s no semicolons — wow! — but you can do multiline statements.  But if you do you better make sure it’s obvious you’re stopping on that line:

def foo a = 0
  a + 1
end

bar = foo 1
bar 
=> 2
bar = foo
1
bar
=> 1
bar = foo(
1)
bar
=> 2

I could go on and on — and indeed as I’m learning I come across more and more of these cases (e.g., in method definitions if you assign something, the left side of the assignment refers to a local variable, but anything on the right side will look for a local definition, then hop to a class-level definition if a local one is not found), and every time I see “except” or “but” or “in this cases” I die a little bit inside.  Many of these “features” are not unique to Ruby, either — I’ve seen these in a thousand places, and as I said, I started out with PHP, which has its own set of terrible, awful, no good, very bad conventions.

In the highly unlikely event you are about to begin designing a language, I urge you to take a step back and think about what you’re doing when you attempt to make things “more convenient.”  Just because you hate typing parentheses doesn’t mean they’re not a useful construct.  If what you’re doing has negligible benefits in the average case, but makes me remember another rule for when I’m allowed to use your shortcut, it’s not a shortcut.  You’ve made my job harder, not easier.  Favor consistency and make it as easy as possible for me to understand what I’m reading and writing without having to clog my head with exceptions to rules.

In the meantime, I’ll stick with Javascript***, thanks.


 

* Apparently also known as the “serial comma,” because that podcast is everywhere.

** But like also maybe don’t trust a website that advertises the following:

Screen Shot 2015-05-23 at 2.38.29 PM
100% not made up that was on the sidebar

*** 100% definitely click on this link if you have ever written any code ever and watch the entire thing if you have not seen it.

Leave a Reply

Your email address will not be published. Required fields are marked *