5

For an Array x, the following are grammatical expressions:

  • puts x[1]
  • [puts(x[1])]
  • [1 + x[1]]

but this:

  • [puts x[1]]

fails to parse with:

syntax error, unexpected tIDENTIFIER, expecting keyword_do or '{' or '('

Why can't the parser figure out this syntax?

sawa
  • 165,429
  • 45
  • 277
  • 381
vladpisanov
  • 145
  • 1
  • 9

2 Answers2

9

I believe this parsing behavior is intentional--not a bug. It's an unfortunate side-effect of Ruby allowing omitted parentheses. This code is, of course, fine:

def f x, y=0
  x + y
end

f 2    # 2
f 2, 3 # 5

But what is the result of this code?

[f 2, 3]

[2,3] or [5]? In order for the syntactical analyzer to handle this code, it would need to understand the arity of the method. But because Ruby is dynamic that cannot be determined until the method call is actually performed.

Rather than allow the ambiguous case, which would surely result in surprising situations during runtime, the designers opted for the (still surprising, but) easily fixable error during parsing.

Note: you could still argue that in the case where it is the last element there is no ambiguity

[3, f 2]
# should be [3, 2]

but I can imagine pulling my hair out if Ruby let's me write that and then slaps me with a syntax error when I add one more element to the end of the array. I can understand the decision to simply not allow omitted parentheses inside arrays.

Max
  • 21,123
  • 5
  • 49
  • 71
  • 3
    It's worth noting (maybe) that there are cases where Ruby will slap you with a syntax error if you add another element to an array, and it is indeed frustrating: `a = [ 2, foo: :bar] # fine` whereas `a = [ 2, foo: :bar, 3] # syntax error` – Simple Lime Nov 14 '17 at 22:29
  • 1
    You can also have `f 2, f 3, 4` which is especially perplexing. – tadman Nov 14 '17 at 23:27
  • @SimpleLime ewww. given that example I'd say Ruby also shouldn't allow omitted braces inside an array – Max Nov 15 '17 at 14:38
6

In Ruby you can often, but not always omit the parentheses around method calls. You've found a case where you can't. Sometimes there's too much ambiguity for Ruby to understand exactly what you want and you must be more specific.

The valid notation here is:

[puts(x[1])]

Though as puts always returns nil, this is really an odd thing to do.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • Right, I'm just using `puts` as a placeholder. It's just odd because, for example CoffeeScript has no issues with this syntax. I wonder why Ruby considers it ambiguous. – vladpisanov Nov 14 '17 at 19:57
  • It's up to the Ruby parser to make sense of this. While the [lexer](https://en.wikipedia.org/wiki/Lexical_analysis) can understand the components you're using, the [parser](https://en.wikipedia.org/wiki/Parsing#Computer_languages) can't deal with the ambiguity. It's not expecting those tokens to be in that order. Maybe you could petition the Ruby core team to fix this, but as it stands it's a consequence of how Ruby's parser is implemented. – tadman Nov 14 '17 at 21:22
  • This does not answer the question at all: why can't Ruby parse `[puts x[1]]`? To me it seems unambiguous, and I'm very surprised by the error. – Max Nov 14 '17 at 21:56
  • @Max It's a limitation of the parser. Like I said, if you want to fix it, you'll have to patch that code and get the core team to pick up on it. – tadman Nov 14 '17 at 22:01
  • @tadman this got me thinking, and I'm pretty sure it's intentional (and well-thought-out) behavior. See my answer. – Max Nov 14 '17 at 22:11