... or so.
Works as expected: http://carc.in/#/r/bp
Broken: http://carc.in/#/r/bt
I think there are two bugs here:
foo, you have commas after each yield. That should be a syntax error.def bar
t = {1, 3, 5}
Tuple.new(
yield t[0],
yield t[1],
yield t[2]
)
end
bar do |j|
pp j
end
Which incorrectly prints 5 three times. Let's try to reduce it:
def bar
t = {1, 3}
Tuple.new(
yield t[0],
yield t[1],
)
end
bar do |j|
pp j
end
Incorrectly prints 3 two times. What if we use an array for t?
def bar
t = [1, 3]
Tuple.new(
yield t[0],
yield t[1],
)
end
bar do |j|
pp j
end
Wait, what? Prints 3 two times again. What if we use regular vars?
def bar
a = 1
b = 3
Tuple.new(
yield a,
yield b,
)
end
bar do |j|
pp j
end
Prints 3 two times. WAT?
Without vars:
def bar
Tuple.new(
yield 1,
yield 3,
)
end
bar do |j|
pp j
end
3 two times. WAT?
In fact, it seems Tuple.new has nothing to do:
def bar
foo(
yield 1,
yield 3
)
end
def foo(*args)
end
bar do |j|
pp j
end
At that point (or maybe two points before) I got the click and AHA moment! It seems the parser is seeing it as this:
foo(
yield(1, (yield 3))
)
And then it seems that yielding inside a yield doesn't generate correct code. I tried this with Ruby:
def bar
foo(
yield 1,
yield 3
)
end
def foo(*args)
end
bar do |j|
p j
end
It gives me a syntax error. And I thought I knew Ruby's grammar... In fact, just this:
def bar
yield 1, yield 3
end
gives a syntax error in Ruby. @jhass Do you have any idea why?
(sorry for the long explanation, but I thought it was an interesting discovery)
Of course, as a workaround until we fix (and understand :-P) this, you can use parenthesis:
def bar
t = {1, 3, 5}
Tuple.new(
(yield t[0]),
(yield t[1]),
(yield t[2]),
)
end
bar do |j|
pp j
end
Woah, good catch.
sorry for the long explanation, but I thought it was an interesting discovery
It sure was :D
Oh, I see, we need to enter the macro language. Now I understand why it's in Tuple#clone :D http://carc.in/#/r/c2
A bit more about this, I found out that this gives a parse error in Ruby:
bar 1, bar 2
And also this:
bar(1, bar 2)
Apparently you can't have a call without parentheses inside another call unless it's the first argument?
They both parse fine in Crystal, though maybe they shouldn't.
I personally think the parsing of bar 1, bar 2 is fine. MoonScript, CoffeeScript, and Nim all allow it.
Yes, Crystal does it right imo (juxtaposition calls or whatever you'd call it)!
So maybe we can close this? Right now if you run the formatter on the Broken example from the original issue it gets formatted to this:
def foo
t = {0, 2, 4}
yield t[0],
yield t[1],
yield t[2]
end
def bar
t = {1, 3, 5}
Tuple.new(
yield t[0],
yield t[1],
yield t[2]
)
end
foo do |i|
pp i
end
bar do |j|
pp j
end
So, using an editor with an automatic formatter reveals the "problem".
And then it seems that yielding inside a yield doesn't generate correct code.
Still true, no? https://carc.in/#/r/z34