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?

Leonel Galán
  • 6,993
  • 2
  • 41
  • 60
  • 2
    `irb` is a bit fragile and has a fair amount of brain damage, you're probably seeing some of that. – mu is too short Feb 19 '13 at 20:40
  • @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? – nzifnab Feb 19 '13 at 20:54
  • 2
    @nzifnab 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. – coreyward Feb 19 '13 at 20:55
  • Oh, well that's fair enough :) That's always bothered me but I guess I never really paid it much mind. – nzifnab Feb 19 '13 at 20:59
  • @nzifnab: Perhaps you should try `h = { if: 'b' };puts h.inspect` instead. – mu is too short Feb 19 '13 at 21:08
  • Interesting. Works as a script, stays silent when entered into IRB. Thanks for the example :) – nzifnab Feb 19 '13 at 21:11

1 Answers1

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
Peter
  • 127,331
  • 53
  • 180
  • 211
  • 1
    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). – coreyward Feb 19 '13 at 20:56
  • @coreyward: indeed. I tried this. I'll add a block of code to my answer to clarify. thanks! – Peter Feb 19 '13 at 20:59
  • 1
    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. – nzifnab Feb 19 '13 at 21:04
  • @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. – mu is too short Feb 19 '13 at 21:13
  • 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. – Peter Feb 19 '13 at 21:16
  • 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. – Leonel Galán Feb 19 '13 at 21:55