IRB - Ruby 1.9.x hash syntax: {if: true} is not equal to {:if => true}
Asked Answered
D

1

6

Long story short, I was writing a method that included an options argument, that will do certain stuff if the value for the key :if, evaluated to true. When I trying the hash in IRB using the new syntax I got a syntax error in IRB, the prompt stays open:

1.9.3p374 :010 > {if: true}
1.9.3p374 :011?>

Using the old syntax, works just fine:

1.9.3p374 :011 > {:if => true}
 => {:if=>true} 

All keywords that start a statement, exhibit the same behavior. E.g. def, do, module, case

Other reserved words that occur in the middle and class work just fine: else, end

My question is: Is this expected behavior, a bug or a limitation?

Dorinda answered 19/2, 2013 at 20:24 Comment(6)
irb is a bit fragile and has a fair amount of brain damage, you're probably seeing some of that.Sowers
@muistooshort that seems pretty unfounded. echo 'puts {if: true}.inspect' > test.rb; ruby test.rb returns: test.rb:1: syntax error, unexpected ':' In what fashion is irb fragile?Cabob
@Cabob Irb has to hold off on execution of the statement until the end, and if it misinterprets a control operator (as it does here) there are additional issues unique to it.Mineralogist
Oh, well that's fair enough :) That's always bothered me but I guess I never really paid it much mind.Cabob
@nzifnab: Perhaps you should try h = { if: 'b' };puts h.inspect instead.Sowers
Interesting. Works as a script, stays silent when entered into IRB. Thanks for the example :)Cabob
F
6

It's challenging to reliably and unambiguously parse things in any language. This is especially true when you start using reserved words. And irb has to go beyond that and provide an interactive model on top of the parser, which is even harder. I personally don't think there's too much value in worrying about cases like this, either as a user of the language or as a maintainer. In my mind, it's better to simply figure out what works and avoid getting into these situations if possible.

You can see some similar behaviors in plain Ruby, outside irb. For example:

puts({if: true})  # no problem, behaves as expected in Ruby 1.9.3.
puts {if: true}   # raises a syntax error in Ruby 1.9.3

To answer your question, is it "expected behavior, a bug or a limitation", I'd say you should ignore irb and compare it to plain Ruby, and if you do this, it works fine. That means it has to be an irb bug.

But is it possible or worthwhile to solve? @coreyward makes a good point in his comment that irb has to delay execution in most cases when it encounters an if. You'd have to look further to know for sure, but you may not be able to unambiguously interpret all cases like this.

My advice: avoid this construct altogether if you can, and don't use reserved words for labels if you can avoid it!

Here's a file you can run with plain Ruby (eg MRI). You should see {:if=>true} in the output to confirm it works.

{if: true}
foo = {if: true}
# if MRI is working, should be able to execute this file without trouble.
p foo
Fisher answered 19/2, 2013 at 20:55 Comment(6)
It's also worth noting that if you introduce assignment everything works as expected. E.g. foo = {if: true} evaluates fine in MRI (though IRB still trips up).Mineralogist
@coreyward: indeed. I tried this. I'll add a block of code to my answer to clarify. thanks!Fisher
All very interesting. The OP's example fails whether in a ruby script or in IRB, but when you throw parenthesis around the puts it works. How confusing! I almost wish they stuck with hash-rocket exclusively. So much easier to understand and far fewer gotchas (and then all hashes are the same instead of 'hashes with string keys use rockets! hashes with reserved labels use rockets! symbols should sometimes use label syntax!) Ugh.Cabob
@nzifnab: The sometimes in your comment is important, you can't use the JavaScript style with symbols such as :$set which show up all over the place when you're working with MongoDB. I just use hashrocket because I know how to type and I have more important things to worry about than when I can and cannot use the JavaScript style notation.Sowers
just to balance this conversation - I really like the new syntax ({a: 'b'} style) because I think it really lightens the code and makes it more readable. I use it exclusively, and seldom hit gotchas. It's not a big problem. I think of it as akin to // vs. /* */ for one-line C comments.Fisher
Thanks for your answer Peter, I'll take it. I agree with you on the cleaner the code looks, and I'll use it whenever is possible.Fuzz

© 2022 - 2024 — McMap. All rights reserved.