From: "Florian Groß" Date: 2005-08-05T11:44:23+09:00 Subject: Re: new block notation (was: Re: ruby-dev summary 26468-26661) Yukihiro Matsumoto wrote: > |Is it really in accordance to Ruby's design mentality to introduce new > |syntax just because parsing the most obvious one is too complex? > > I didn't choose -> syntax just because "the most obvious one is too > complex". Pardon the trollish oversimplification and thanks for the detailed explanation. It was very informative. This is probably the wrong place to ask, but is there resources that explain the evolution of Ruby's design in detail? It is something that I find very interesting. > Block parameters are destination of multiple assignment. It was > natural since it was designed to be loop variables. Later on, > closures were introduced. Closure, or function object has different > requirement for their parameters. > > * loop variables requires no strict check, it is OK to ignore given > value in the loop body. But method does strict check. I think > closures as well. I think that the check is not strictly necessary in blocks. I guess it could be argued about if it is necessary to have it for lambdas. Or can we just add the check to all blocks and lambdas? This would mean that multiple assignment semantics are totally gone and that [1, 2, 3].each_with_index { |x| p x } would no longer work which might be a good thing, anyway. Ignoring values has been troublesome even with multiple assignment because of the array assignment effect anyway. > * since block parameters are multiple assignment, it does have some > weird behavior in corner cases, especially when arrays and values > associated in left hand expression. Hmmm, yes. > In short, their have been some big (well, at least for me) semantic > gap in block parameters since closures come into the language. This > is a good chance to fix. I see, but currently I don't think I like the fix. I think I would prefer to keep the current semantics instead of x = ->(a) { ... } Here's another try to come up with an alternative: [1, 2, 3].inject { |a| a } # => 1 [1, 2, 3].inject { |*a| a } # => [[1, 2], 3] I think both would eventually not produce warnings. The first could still emit a warning for a short period to get users used to the change. There is at least two options regarding default and keyword arguments in block argument lists. Option A: def x() yield(1, 2, 5); yield(1, 2) end; def y() yield(c: 5); yield() end x { |a, b, c = (a | b)| p c } # outputs 5, 3 y { |a: 0, b: 0, c: (a | b)| p c } # outputs 5, 0 Option B: No default values and keyword arguments for blocks. (Rarely needed anyway.) adder = fun(a, b) -> { a + b } or adder = fun(a, b) { a + b } And these would have exactly the same semantics as method calls. The problem with this approach is that it officially makes a split between blocks and anonymous functions, but it easily allows to ignore arguments in iterators. If ignoring arguments in iterators is not as important as simplicity there is not much of a reason to ignore a new syntax IMHO. In that case this could be done: [1, 2, 3].inject { |a| a } # ArgumentError at yield # I think ,* makes a lot of sense for ignoring everything from here on # and I think it fits visually well as well [1, 2, 3].inject { |a,*| a } # 1 [1, 2, 3].inject { |*a| a } # [[1, 2], 3] And we would still use lambda: adder = lambda { |a, b| a + b } alias :λ :lambda # I wonder if Unicode names will ever be in core Ruby adder = λ { |a, b| a + b } Even in this situation it still needs to be decided if keyword and default arguments should be possible for both lambda and blocks. I feel a bit like I have lost a line of thought, somehow. I hope this still looks sane. I really don't understand the idea behind x = ->(a, b) { ... } -- it makes as much sense as x = ^^(a, b) { ... } to me so I would like if it would not replace the anonymous functions or blocks I use so frequently. > |I also think that you might be able to fix the arrow syntax by moving > |it. I think something like this is acceptable: > | > |adder = (a, b) -> { a + b } > > Again, I don't think yacc would allow this. I wonder how perl parses code. I think they are doing a lot of semantic look-ahead. Doesn't help with parsing of humans, though. > |This is again very hard to parse. Perhaps even for humans. So: > | > |adder = \(a, b) -> { a + b } > |printer = \a -> { puts a } > > I don't want to use backslashes just for yen-sign problem, besides > this particular idea requires even more punctuation. It is an > unfortunate character (at least in Japan) which has totally different > appearance between fontset. For example, '\' above can be seen as a > backslash on my Emacs, yen-sign on my browser, only if the page > contains any Japanese characters. That might be my personal problem, > but I consider myself very important in the design process of the Ruby > language. I don't think it is a personal problem of you. It would likely be a huge problem for all Japanese Ruby users then (After all posting code on the web is fairly common.) and it would probably a bad idea to spoil the language for those. :) -- Had I known about it I would not have suggested using backslashes.