Feature #8956
closedAllow hash members delimited by \n inside of {}
Description
Currently, hashes require members to be delimited by commas (,
), even inside curly braces. E.g.,
some_hash = {
:foo => 'bar',
:bar => 'foo',
:baz => {
:qux => 'quux',
:corge => 'grault'
}
}
In my opinion, these commas add nothing of value to this particular example since, visually, the members are already delimited by a newline (\n
). Additionally, missing a comma between members results in syntax error, unexpected tSYMBEG, expecting '}'
.
I propose we make these commas optional, such that the following syntax would be possible:
some_hash = {
:foo => 'bar'
:bar => 'foo'
:baz => {
:qux => 'quux'
:corge => 'grault'
}
}
This change would not affect existing hashes. Developers would be able to mix and match the old and new syntaxes as such:
some_hash = {
:foo => 'bar'
:bar => 'foo'
:baz => {
:foo => 'bar' + 'baz'
:bar => 'foo', :qux => 'quux'
:corge => 'grault'
}
}
This change would also reduce the occurrence of syntax errors in cases where the developer temporarily replaces a value in the hash, e.g.,
some_hash = {
:this => 'that',
:foo => 'not bar'#'bar',
:those => 'the other'
}
Finally, this change would only affect hashes inside curly braces (for hopefully obvious reasons).
I have attached a diff of my suggested changes along with a script to test a variety of use cases. I also have an open pull request on GitHub: URL:https://github.com/ruby/ruby/pull/402
Please let me know if there's anything I've missed or that needs clarification.
Files
Updated by adamdunson (Addie Drake) about 11 years ago
I feel the need to mention that at this time, my changes do not include Ruby 1.9 style symbol hashes. These still require commas, e.g.,
some_hash = {
foo: 'bar',
bar: 'foo',
baz: {
qux: 'quux',
corge: 'grault'
}
}
Updated by nobu (Nobuyoshi Nakada) about 11 years ago
Additional patch for labeled assocs
.
diff --git a/parse.y b/parse.y
index b0a7cc4..63b4334 100644
--- a/parse.y
+++ b/parse.y
@@ -5013,4 +5013,7 @@ trailer : /* none */
assoc_seperator : '\n'
+ {
+ command_start = FALSE;
+ }
| ','
;
Updated by alexeymuranov (Alexey Muranov) about 11 years ago
Same about arrays, i guess? :)
Updated by sawa (Tsuyoshi Sawada) about 11 years ago
If this proposal is going to be considered, then I think it should not be just for hashes, but also for arrays, and for arguments passed to a method.
[
:foo
:bar
]
foo(
"arg1"
"arg2"
)
Also note that, since "\n"
should be replacable by ";"
, the proposal would mean the following is allowed:
{:foo => 1; :bar => 2}
Updated by adamdunson (Addie Drake) about 11 years ago
Thanks for the patch, nobu. That was easier than I thought it would be; I was looking in the wrong place entirely.
sawa (Tsuyoshi Sawada) wrote:
[...] I think it should not be just for hashes, but also for arrays, and for arguments passed to a method.
I agree. Hashes were the easiest to tackle, but I have also been working on a solution for arrays and arguments. I'm definitely open to suggestions if anyone figures it out before I do.
sawa (Tsuyoshi Sawada) wrote:
Also note that, since
"\n"
should be replacable by";"
, the proposal would mean the following is allowed:{:foo => 1; :bar => 2}
Is this a desired effect? My current patch does not account for this, but it shouldn't be difficult to add support for it.
Updated by adamdunson (Addie Drake) about 11 years ago
- File add-array-support.patch add-array-support.patch added
I've attached a patch for array support (only between square brackets). I've also renamed the assoc_seperator
rule to be nl_or_comma
to make it a little more generic.
This allows for syntax similar to hashes (here's a rather complex example):
some_array = [
:foo
:bar
[
'baz'
:qux
]
{
:quux => 'grault'
'garply' => [
'waldo' => :fred
]
:plugh => 'xyzzy'
}
]
Updated by adamdunson (Addie Drake) about 11 years ago
Adding a patch for method argument support. For example, this allows the following syntaxes:
Hash[
:foo, 'bar'
:baz, 'qux'
]
which becomes { :foo => "bar", :baz => "qux" }
, as well as
puts("this is line one"
"this is line two"
"this is line three")
Updated by adamdunson (Addie Drake) about 11 years ago
Sorry, the previous patch was incorrect (add-method-arg-support.patch). Please use the attached version instead.
Updated by adamdunson (Addie Drake) about 11 years ago
I should also mention that this patch does not apply to method definitions, so these still require commas (at least, for now):
def some_method(foo,
bar,
baz)
# do stuff
end
Updated by sawa (Tsuyoshi Sawada) about 11 years ago
Another case where similar syntax might be relevant is | |
inside a block. Whether you want to do this:
{|
foo
bar
baz
| ....}
should go together with whether arguments in method definition can be written as:
def foo(
foo
bar = some_complicated_expression_as_default_value
baz = maybe_another_complicated_default_value
)... end
The latter is useful if you want to put some complicated expression as default value. Usefulness of the former would depend on whether default value would be allowed for block variables.
Updated by sawa (Tsuyoshi Sawada) about 11 years ago
I also thought that maybe you can go one step further and allow any sequence of white characters as delimiters when the parentheses/braces/brackets/pipes are not omitted:
foo(:foo :bar :baz)
{foo: "bar baz: "qux"}
[:foo :bar :baz]
foo{|foo bar baz| ...}
Updated by adamdunson (Addie Drake) about 11 years ago
Hi sawa,
Another case where similar syntax might be relevant is
| |
inside a block. ... should go together with ... arguments in method definition
I agree. Arguments in method definitions have been on my to-do list — I haven't had much time lately to look at this, but good call on allowing newlines inside vertical bars in a block.
I also thought that maybe you can go one step further and allow any sequence of white characters as delimiters when the parentheses/braces/brackets/pipes are not omitted
I like the idea, but this one might be too ambitious. The problem that I see is that it introduces ambiguity when passing a method as an argument, e.g.,
def foo(a, b = 0, c = 0)
puts a + b + c
end
def bar(a = 0)
a + 1
end
foo(bar 1 2)
In this instance, it is difficult to tell whether foo
is being called with three arguments (bar
, 1
, and 2
) or with two arguments (bar(1)
and 2
).
Updated by sawa (Tsuyoshi Sawada) about 11 years ago
adamdunson,
As I wrote already, omission of comma is to be allowed only when the ()[]{}|
is not omitted.
foo(bar 1 2)
would be unambiguously foo
taking three arguments bar
, 1
, and 2
.
Updated by adamdunson (Addie Drake) about 11 years ago
sawa,
Could you elaborate? I still find that expression to be ambiguous. Here's another example that works with ruby 2.0.0-p247:
def foo(a, b = 0, c = 0)
a + b + c
end
def bar(a = 1, b = 0)
a + b
end
puts foo(bar 1, 2) # outputs 3
puts foo(bar, 1, 2) # outputs 4
If spaces and commas were made to be interchangeable inside parentheses, then the above two calls to foo
would be equivalent (which they are not).
Updated by adamdunson (Addie Drake) about 11 years ago
- File no-comma-tests.patch no-comma-tests.patch added
Adding another patch with tests for no-comma hashes, arrays, and method arguments.
Updated by timrosenblatt (Tim Rosenblatt) about 11 years ago
bump? This looks helpful.
Updated by timrosenblatt (Tim Rosenblatt) about 11 years ago
Bump again. Can we get a thumbs up or down on this?
As a gift, here is a picture of a very happy cat. http://www.freefever.com/stock/comic-pet-desktop-very-happy-cat.jpg
URL:http://www.freefever.com/stock/comic-pet-desktop-very-happy-cat.jpg
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Description updated (diff)
- Status changed from Open to Rejected
It seems this issue has diverged so far from the original.
I reject it for now.
Updated by alexeymuranov (Alexey Muranov) about 10 years ago
I have proposed another version: #10528.