Hashes don't allow preceding commas by design?

This is the output from irb that shows ruby 1.9.1 doesn’t like hash
entries to be preceded by a comma, only ended by one:

myhash3 = {
:first => “first”,
:second => “second”
}
{:first=>“first”, :second=>“second”}

myhash3 = {
:first => “first”
, :second => “second”
}
SyntaxError: (irb):48: syntax error, unexpected ‘,’, expecting ‘}’
, :second => “second”
^
from /Library/Frameworks/Ruby.framework/Programs/irb:12:in `’

I prefer to put my comma’s at the front of a line as it makes a line
easier and quicker to comment out (1 vs 2 lines and a lot less fiddly).
Is this only-commas-at-the-end by design or did I miss something? I’ve
tested this with a script and with irb.

Quick addendum, thought I’d test this for arrays too, and it’s the same.

myarr = [ 1, 2, 3]
[1, 2, 3]

myarr2 = [
1,
2,
3
]
[1, 2, 3]

myarr3 = [
1
,2
,3
]
SyntaxError: (irb):58: syntax error, unexpected ‘,’, expecting ‘]’
from /Library/Frameworks/Ruby.framework/Programs/irb:12:in `’

Iain

On Wed, Jul 7, 2010 at 3:23 AM, Iain B. [email protected]
wrote:

:first => “first”
only-commas-at-the-end by design or did I miss something? I’ve tested this
3

Iain

I don’t know the reasoning for that decision [quirk?] but commas at the
end
of lines should not hinder commenting out lines

a = {
1 => 2 ,
3 => 4 ,
5 => 6 ,
}
a # => {5=>6, 1=>2, 3=>4}

a = {

1 => 2 ,

3 => 4 ,
5 => 6 ,
}
a # => {5=>6, 3=>4}

a = {
1 => 2 ,

3 => 4 ,

5 => 6 ,
}
a # => {5=>6, 1=>2}

a = {
1 => 2 ,
3 => 4 ,

5 => 6 ,

}
a # => {1=>2, 3=>4}

It’s not hashes it is the parser in general. When it parses a line (up
to
the newline) if the line appears compete then the parser expects a new
statement on the next line. So with

1: => a, b = 1,
2: => 2

Line 1 is incomplete so the parser treats line 2 as a continuation of
line

  1. But with

1: => a, b = 1
2: => ,2

Line 1 is complete in that the line contains a valid Ruby statement so
the
parser expects the next line to be a new statement, line 2 is in error
because no valid Ruby statements start with a comma.

This is what you are seeing in your examples.

On 7 Jul 2010, at 09:36, Peter H. wrote:

1: => a, b = 1
2: => ,2

Line 1 is complete in that the line contains a valid Ruby statement so the
parser expects the next line to be a new statement, line 2 is in error
because no valid Ruby statements start with a comma.

This is what you are seeing in your examples.

Thanks, I’m still getting used to Ruby’s ways.

Iain

On Wed, Jul 7, 2010 at 3:36 AM, Peter H. <
[email protected]> wrote:

1: => a, b = 1
2: => ,2

Line 1 is complete in that the line contains a valid Ruby statement so the
parser expects the next line to be a new statement, line 2 is in error
because no valid Ruby statements start with a comma.

This is what you are seeing in your examples.

I think that I feel this should not be the case, because I feel that the
interpreter should not consider any of it complete since it is inside of
an
incomplete hash.

However, these examples have me so unsure of what is supposed to be what
that I can’t construct a response illustrating this. Please double check
these examples.

On 7 Jul 2010, at 09:33, Josh C. wrote:

}

a = {
1 => 2 ,
3 => 4 ,

5 => 6 ,

}
a # => {1=>2, 3=>4}

If you’re allowed a comma for the last line then it’s not a problem.
Thanks for letting me know, too many years working with languages that
don’t like that meant I didn’t try it :slight_smile:

Iain

On Wed, Jul 7, 2010 at 4:36 AM, Peter H. <
[email protected]> wrote:

On 7 July 2010 10:15, Josh C. [email protected] wrote:

However, these examples have me so unsure of what is supposed to be what
that I can’t construct a response illustrating this. Please double check
these examples.

1: => a = { :fred => 42 }

Okay, I found the point of confusion. The confusion is that "1: => " is
not
trying to create a hash table, but is rather a way of identifying line
numbers. I was opening irb in all my different rubies seeing if it would
accept
{ 1: => a = { :fred => 42 } }

Line 3 is complete in that it is a valid statement that can be found inside
a hash declaration but the parser is still looking for the closing } to
match the opening { from line 2. So although line 3 is a complete valid
statement it is part of lines 1 and 2 which is an incomplete hash
declaration.

So line 4 is taken to be a continuation of lines 1, 2 and 3 and finally
completes the statement that started on line 1.

Your explanation implies to me that the OP’s desired use case is valid.
If
“line 4 is taken to be a continuation of lines 1, 2 and 3” then how come
line 4 can’t be “,:jim => 43”

On 7 July 2010 10:15, Josh C. [email protected] wrote:

I think that I feel this should not be the case, because I feel that the
interpreter should not consider any of it complete since it is inside of an
incomplete hash.

However, these examples have me so unsure of what is supposed to be what
that I can’t construct a response illustrating this. Please double check
these examples.

The structure of a has assignment could be either:

1: => a = { :fred => 42 }

or

1: => a =
2: => {
3: => :fred => 42
4: => }

Here line 1 is incomplete so it treats line 2 as a continuation. Line 2
says
‘here is the start of a hash’ and is also incomplete. So line 3 is seen
as a
continuation of line 2.
Line 3 is complete in that it is a valid statement that can be found
inside
a hash declaration but the parser is still looking for the closing } to
match the opening { from line 2. So although line 3 is a complete valid
statement it is part of lines 1 and 2 which is an incomplete hash
declaration.

So line 4 is taken to be a continuation of lines 1, 2 and 3 and finally
completes the statement that started on line 1.

Iain B. wrote:

myhash3 = {
:first => “first”
, :second => “second”
}

It is possible if you force the Ruby Interpreter to look at that line to
be incomplete:

myhash3 = {
:first => “first”
, :second => “second”
}

But I don’t necessarily like this, since the backslash looks so
misplaced in a nice language like Ruby…

Marvin

Peter H. wrote:

So if we read through a couple of examples:

1: {
2: :first => 1,
3: :second => 2
4 }

But I think the question is why the following isn’t allowed:

{
:first => 1
,
:second => 2
}

I’d say it’s just a quirk of the parser, and/or the fact that the
language doesn’t have a formal grammar.

On 7 July 2010 11:02, Josh C. [email protected] wrote:

So line 4 is taken to be a continuation of lines 1, 2 and 3 and finally
completes the statement that started on line 1.

Your explanation implies to me that the OP’s desired use case is valid. If
“line 4 is taken to be a continuation of lines 1, 2 and 3” then how come
line 4 can’t be “,:jim => 43”

I can understand the confusion but it can be explained like this

“A hash is a ‘{’ followed by a comma separated list of key / value pairs
finished off with a ‘}’”

So if we read through a couple of examples:

1: {
2: :first => 1,
3: :second => 2
4 }

Line 1 starts the hash declaration, the parser is looking for a key
value
pair or a ‘}’
Line 2 is a key value pair and a comma. The comma tells the parser than
it
should expect another key value pair
Line 3 is the next key value pair and does not have a comma. So the
parser
has come to the end of the list of key value pairs that makes up a hash
and
is therefore expecting a ‘}’
Line 4 is the expected ‘}’ and the hash declaration is complete

Now try this:

1: {
2: :first => 1
3: :second => 2
4 }

Again line 1 starts the hash declaration, the parser is looking for a
key
value pair or a ‘}’
Line 2 is a key value pair and does not have a comma. So the parser
believes
that it has come to the end of the list of key value pairs and is
therefore
expecting a ‘}’
Line 3 is a key value pair but the parser is expecting a ‘}’ so this is
an
error. The compiler spits out the error.
We never get to line 4.

This goes back to what I said about ‘incomplete’ lines “:first => 1,” is
incomplete because the comma makes the parser think that another key
value
pair should be expected because it is parsing a hash declaration. So
line 3
is treated as a continuation of line 2 and all is well with the world.

However “:first => 1” is a complete line, the absence of a comma does
not
set the parser up to expect another key value pair. So when it
encounters
“:second => 2” it goes “what is going on here, according to my rules the
next thing I should find is an ‘}’”.

It is not to say that the parser couldn’t handle this situation or at
least
handle a line like “, :second => 2” (with a leading comma) but it does
not
as currently implemented.

Some languages use things like a ‘;’ as an explicit end of statement
marker
to help the parser. Ruby does not do this and treats the end of a line
to be
the implicit end of statement marker unless the statement appears to be
incomplete. What constitutes incomplete depends on what it is parsing, a
hash, a list, an if statement etc.

On 7 July 2010 13:43, Brian C. [email protected] wrote:

But I think the question is why the following isn’t allowed:

{
:first => 1
,
:second => 2
}

Look at this in irb might help us understand it

irb(main):001:0> a = {
irb(main):002:1* :first => 1
irb(main):003:1> ,
irb(main):004:1* :second => 2
irb(main):005:1> }
SyntaxError: compile error
(irb):3: syntax error, unexpected ‘,’, expecting ‘}’
from (irb):4
from :0

The irb prompt ends with a > if it is looking for a new line. When it
ends
with a *, as in line 2, it means that the parser thinks that the
pervious
line is incomplete and that line 2 is a continuation of line 1.

However after entering line 2 the prompt returns to a >. This means that
the
parser thinks that line 2 was complete and there is nothing more to be
read.
Compare it to this

irb(main):001:0> a = {
irb(main):002:1* :first => 1,
irb(main):003:1* :second => 2
irb(main):004:1> }

The comma is on the end line 2 and the prompt for line 3 ends with a *.
The
parser shows us that it does not consider line 2 to be complete and that
line 3 will be treated as a continuation of line 2.

A line ending with a comma tells the parser that (in the cases where a
comma
is used such as hashes, lists or functions) that the statement is
incomplete
and to treat the next line as a continuation of this line.

I’m not saying that the parser could not be written to handle the case
you
present it is just that with the present design that uses the end of
line as
an implicit end of statement marker the behaviour you are seeing is the
expected behaviour.

The same thing happens with the if statement

if some_test ||
another_test

will parse the same as

if some_test || another_test

but

if some_test
|| another_test

is something else entirely.

“if some_test” on a line by itself is a complete statement so the parser
is
expecting the statement block (or a “then”) but “if some_test ||” is
incomplete as || needs something on the right hand side so it treats the
next line as a continuation of the current one.