New block notation (was: Re: ruby-dev summary 26468-26661)

(Martin Elzen) #1

Now ruby(HEAD) accepts the notation '->(...){...}'

I like that new block notation as well. Somehow it's always felt just the slightest bit 'off', to me, to specify a block's arguments within the block... The new notation seperates the specification of a block's arguments (which doesn't really belong *in* the block, somehow, IMO) from the code that says what you're going to *do* with those arguments (which certainly does belong in the block)... The new way feels just a slight bit more correct, somehow.

(Brian Wisti) #2

Aww, but now it looks even less like Smalltalk! I kid, I will live
just fine with either notation style, although I prefer the current
style. I'll keep on using the current style for as long as it is
available, for one simple reason: less punctuation.

Kind Regards,

Brian Wisti
http://coolnamehere.com/

···

On 8/4/05, Martin Elzen <martinelzen@hotmail.com> wrote:

>Now ruby(HEAD) accepts the notation '->(...){...}'

I like that new block notation as well. Somehow it's always felt just the
slightest bit 'off', to me, to specify a block's arguments within the
block... The new notation seperates the specification of a block's
arguments (which doesn't really belong *in* the block, somehow, IMO) from
the code that says what you're going to *do* with those arguments (which
certainly does belong in the block)... The new way feels just a slight bit
more correct, somehow.

(Vincent Foley) #3

Hi,

this is the first time I see this thread, and I was wondering *why*
change the block syntax? I quite like it the way it is now, it's easy
to type, easy to read and my fingers are used to it now.

(Yukihiro Matsumoto) #4

Hi,

···

In message "Re: new block notation (was: Re: ruby-dev summary 26468-26661)" on Fri, 5 Aug 2005 03:23:40 +0900, Brian Wisti <brian.wisti@gmail.com> writes:

Aww, but now it looks even less like Smalltalk! I kid, I will live
just fine with either notation style, although I prefer the current
style. I'll keep on using the current style for as long as it is
available, for one simple reason: less punctuation.

That's OK. The new notation is to replace lambda.

              matz.

(Eric Mahurin) #5

Hi,

>Aww, but now it looks even less like Smalltalk! I kid, I
will live
>just fine with either notation style, although I prefer the
current
>style. I'll keep on using the current style for as long as
it is
>available, for one simple reason: less punctuation.

That's OK. The new notation is to replace lambda.

              matz.

I noticed this experimental behavior disappeared:

f = { ... code .. }

So this new syntax tries to address 2 issues:

1. Allowing args to have defaults in a block.

2. Making a lambda without the "lamda", "proc", or "Proc.new"
... and also not cause ambiguities with a Hash.

So before, the experiment was this (no default args and
ambiguities with Hash):

f = { |a| ... }

and now you are thinking about this:

f = ->(a) { ... }

To me, this suffers readability because there are too many
symbols in a row: =->( Wasn't this kind of thing the primary
problem with perl - too many punctuation characters made it
difficult to read.

It seems like you are between a rock and a hard place
(preserving backwards compatibility) to solve this problem. I
don't see one great solution. The best I can come up with is
to use syntax like we have now except a) use symbols other than

that allow no ambiguity in the expressions (I think :+space

would work), and b) force an argument list to not cause
ambiguities. So you'd have this:

f = { : a,b=1|2 : ... }
f = { : * : ... } # equivalent to f = lambda { ... }

Still kind of ugly though. Too bad you have to leave hashes as
first-class. If you made them second class instead (
hash(key=>value,...) or Hash.new(key=>value,...)), that would
allow more freedom. I think code blocks are much more
important than hashes.

···

--- Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

In message "Re: new block notation (was: Re: ruby-dev summary > 26468-26661)" > on Fri, 5 Aug 2005 03:23:40 +0900, Brian Wisti > <brian.wisti@gmail.com> writes:

____________________________________________________
Start your day with Yahoo! - make it your home page

(Yukihiro Matsumoto) #6

Hi,

So before, the experiment was this (no default args and
ambiguities with Hash):

f = { |a| ... }

and now you are thinking about this:

f = ->(a) { ... }

To me, this suffers readability because there are too many
symbols in a row: =->( Wasn't this kind of thing the primary
problem with perl - too many punctuation characters made it
difficult to read.

I don't agree. Punctuation symbol nor sequence of them itself is not
a problem. The problems can be caused by context dependent
interpretation of symbols, I think.

It seems like you are between a rock and a hard place
(preserving backwards compatibility) to solve this problem. I
don't see one great solution. The best I can come up with is
to use syntax like we have now except a) use symbols other than

that allow no ambiguity in the expressions (I think :+space

would work), and b) force an argument list to not cause
ambiguities. So you'd have this:

f = { : a,b=1|2 : ... }
f = { : * : ... } # equivalent to f = lambda { ... }

Unfortunately :+space causes conflicts as well.

              matz.

···

In message "Re: new block notation (was: Re: ruby-dev summary 26468-26661)" on Fri, 5 Aug 2005 07:55:54 +0900, Eric Mahurin <eric_mahurin@yahoo.com> writes:

(Ara.T.Howard) #7

Hi,

>Aww, but now it looks even less like Smalltalk! I kid, I
will live
>just fine with either notation style, although I prefer the
current
>style. I'll keep on using the current style for as long as
it is
>available, for one simple reason: less punctuation.

That's OK. The new notation is to replace lambda.

              matz.

I noticed this experimental behavior disappeared:

f = { ... code .. }

So this new syntax tries to address 2 issues:

1. Allowing args to have defaults in a block.

2. Making a lambda without the "lamda", "proc", or "Proc.new"
... and also not cause ambiguities with a Hash.

So before, the experiment was this (no default args and
ambiguities with Hash):

f = { |a| ... }

and now you are thinking about this:

f = ->(a) { ... }

how about something a little more mathematical

   f <- {|a = 42| p a}

or even

   f <= {|a = 42, b <= {p 42}| p a; b.call }

so <- or <= mean 'function assignment'

probably someone already suggested this... this thread has been long :wink:

Still kind of ugly though. Too bad you have to leave hashes as first-class.
If you made them second class instead ( hash(key=>value,...) or
Hash.new(key=>value,...)), that would allow more freedom. I think code
blocks are much more important than hashes.

i dunno - if i were stuck on a desert island with only one programming
artifact it'd surely be a hash - and just about any real code requires good
data structures...

cheers.

-a

···

On Fri, 5 Aug 2005, Eric Mahurin wrote:

--- Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

In message "Re: new block notation (was: Re: ruby-dev summary >> 26468-26661)" >> on Fri, 5 Aug 2005 03:23:40 +0900, Brian Wisti >> <brian.wisti@gmail.com> writes:

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
My religion is very simple. My religion is kindness.
--Tenzin Gyatso

===============================================================================

(Austin Ziegler) #8

I don't. I use hashes more than I use anonymous code blocks (lambdas). Far more.

-austin

···

On 8/4/05, Eric Mahurin <eric_mahurin@yahoo.com> wrote:

Still kind of ugly though. Too bad you have to leave hashes as
first-class. If you made them second class instead (
hash(key=>value,...) or Hash.new(key=>value,...)), that would
allow more freedom. I think code blocks are much more
important than hashes.

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

(Martin DeMello) #9

That's rather drastic. All it needs is a new symbol for literal hashes.
(I like [| |] myself.)

martin

···

Eric Mahurin <eric_mahurin@yahoo.com> wrote:

Still kind of ugly though. Too bad you have to leave hashes as
first-class. If you made them second class instead (
hash(key=>value,...) or Hash.new(key=>value,...)), that would
allow more freedom. I think code blocks are much more
important than hashes.

(Joel VanderWerf) #10

Ara.T.Howard wrote:

how about something a little more mathematical

  f <- {|a = 42| p a}

or even

  f <= {|a = 42, b <= {p 42}| p a; b.call }

so <- or <= mean 'function assignment'

Ugh. It's still assigning a value to a variable. Why should the syntax
be different when the value has a different class? I'd rather stick with
proc or lambda, or, more generally, have some special syntax for
instantiating a proc rather than for assigning a proc.

Think about what appens when you refactor:

  f <- {|a = 42| p a}

to

  b = get_a_proc_from_something
  f <- b

oops, error. Now it has to be:

  f = b

Also, what about method arguments?

foo({|a=42| p a})

Does this need special syntax to resolve an ambiguity? I haven't
followed the thread well enough to know the answer...

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

(Eric Mahurin) #11

Wouldn't work:

a. doesn't solve the problem that the default "value" can be an
expression that has a "|" in it.

b. you can do more with lambda's other than just assign them.
You can pass them as arguments, call their methods (i.e. arity,
call), and in general they should just be another object in an
expression. Treating the assignment of a lambda special this
way doesn't make sense.

c. the <= form looks like the less than or equal operator.

···

--- "Ara.T.Howard" <Ara.T.Howard@noaa.gov> wrote:

On Fri, 5 Aug 2005, Eric Mahurin wrote:

> --- Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
>
>> Hi,
>>
>> In message "Re: new block notation (was: Re: ruby-dev > summary > >> 26468-26661)" > >> on Fri, 5 Aug 2005 03:23:40 +0900, Brian Wisti > >> <brian.wisti@gmail.com> writes:
>>
>> >Aww, but now it looks even less like Smalltalk! I kid, I
>> will live
>> >just fine with either notation style, although I prefer
the
>> current
>> >style. I'll keep on using the current style for as long
as
>> it is
>> >available, for one simple reason: less punctuation.
>>
>> That's OK. The new notation is to replace lambda.
>>
>> matz.
>
> I noticed this experimental behavior disappeared:
>
> f = { ... code .. }
>
> So this new syntax tries to address 2 issues:
>
> 1. Allowing args to have defaults in a block.
>
> 2. Making a lambda without the "lamda", "proc", or
"Proc.new"
> ... and also not cause ambiguities with a Hash.
>
> So before, the experiment was this (no default args and
> ambiguities with Hash):
>
> f = { |a| ... }
>
> and now you are thinking about this:
>
> f = ->(a) { ... }

how about something a little more mathematical

   f <- {|a = 42| p a}

or even

   f <= {|a = 42, b <= {p 42}| p a; b.call }

so <- or <= mean 'function assignment'

probably someone already suggested this... this thread has
been long :wink:

____________________________________________________
Start your day with Yahoo! - make it your home page

(Austin Ziegler) #12

So before, the experiment was this (no default args and
ambiguities with Hash):

f = { |a| ... }

and now you are thinking about this:

f = -> (a) { ... }

To me, this suffers readability because there are too many
symbols in a row: =-> ( Wasn't this kind of thing the primary
problem with perl - too many punctuation characters made it
difficult to read.

I don't agree. Punctuation symbol nor sequence of them itself is
not a problem. The problems can be caused by context dependent
interpretation of symbols, I think.

Mmmm. I think that part of Perl's problem *is* overpunctuation. I do
sort of like Ara's suggestion (e.g., f <- { |...| ... }) for
lambdas, but understand that would probably cause as many problems
as anything else (and I think that f = <- { |...| ... } is just
ugly).

It seems like you are between a rock and a hard place (preserving
backwards compatibility) to solve this problem. I don't see one
great solution. The best I can come up with is to use syntax like
we have now except a) use symbols other than | that allow no
ambiguity in the expressions (I think :+space would work), and b)
force an argument list to not cause ambiguities. So you'd have
this:

f = { : a,b=1|2 : ... }
f = { : * : ... } # equivalent to f = lambda { ... }

Unfortunately :+space causes conflicts as well.

What about "|:"? That is:

  f = { | foo, bar = 1 | 2 |: ... }

That might also make it possible to do:

  f = { foo, bar = 1 | 2 |: ... }

dropping the first pipe, which would also be a nice visual indicator
that this block has full method semantics rather than closure
semantics (if that distinction iss important, necessary, or
continued).

Even with what I suggested to Eric about using Hashes more than
Blocks, I think it would be nice to have a different syntax for
blocks and hashes, and I think that it's probably easier to redo
hashes for Ruby 2.0 than blocks.

My personal vote would be for one of these:
  [: key => value :]
  [: key: value :]

I'm not saying it'd be great -- it's easier for me to type "{" than
"[:", but I think that I could learn to live with it. (Alternately,
overload the [] syntax so that if it looks like a Hash inside, it
*is* a Hash.)

-austin

···

On 8/4/05, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

In message "Re: new block notation (was: Re: ruby-dev summary > 26468-26661)" on Fri, 5 Aug 2005 07:55:54 +0900, Eric Mahurin > <eric_mahurin@yahoo.com> writes:

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

(Eric Mahurin) #13

It does? How so? I said :+space to not conflict with the
:symbol syntax (could be a hash), just like the ? : operator.
I also don't think this conflicts with the ? : operator. If
you have this:

f = { : a = cond ? x : y : ... }

That middle : should obviously be interpreted as part of the ?
: operation. Similar to the way a newline doesn't terminate a
statement if it is in the middle of the statement.

Another option would be to use the ;/newline punctuation to
separate the args from the code:

f = { : a, b ; ... }

or

f = { : a, b
    ...
}

If you didn't have to deal with hash ambiguities and you could
say that the arg list is required, I'd suggest this (remove the
: above):

f = { a,b ; ... }
f = { a,b
    ...
}
f = { ; ... }
f = {
    ...
}

To me that is about the prettiest you could get. Just my 2
cents.

BTW, I noticed that lambdas without args now is interpreted as
no args allowed instead of any number of args allowed:

f = lambda { "xyz" };p(f["hi"])

wrong number of arguments (1 for 0) (ArgumentError)

1.8.2 allows this. Was this change intentional?

···

--- Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

>f = { : a,b=1|2 : ... }
>f = { : * : ... } # equivalent to f = lambda { ... }

Unfortunately :+space causes conflicts as well.

____________________________________________________
Start your day with Yahoo! - make it your home page

(David A. Black) #14

Hi --

···

On Fri, 5 Aug 2005, Yukihiro Matsumoto wrote:

Hi,

In message "Re: new block notation (was: Re: ruby-dev summary 26468-26661)" > on Fri, 5 Aug 2005 07:55:54 +0900, Eric Mahurin <eric_mahurin@yahoo.com> writes:

>So before, the experiment was this (no default args and
>ambiguities with Hash):
>
>f = { |a| ... }
>
>and now you are thinking about this:
>
>f = ->(a) { ... }
>
>To me, this suffers readability because there are too many
>symbols in a row: =->( Wasn't this kind of thing the primary
>problem with perl - too many punctuation characters made it
>difficult to read.

I don't agree. Punctuation symbol nor sequence of them itself is not
a problem. The problems can be caused by context dependent
interpretation of symbols, I think.

But if you had a language (and I imagine there is one somewhere :slight_smile:
that used unique strings of punctuation for all its keywords, it would
look pretty bad. Obviously that's not an issue here, but it does
suggest that there can be such a thing as too much punctuation, even
if it's unambiguous.

David

--
David A. Black
dblack@wobblini.net

(Florian Gross) #15

Yukihiro Matsumoto wrote about new lambda syntaxes:

>f = ->(a) { ... }

[...]

>f = { : a,b=1|2 : ... }
>f = { : * : ... } # equivalent to f = lambda { ... }

Unfortunately :+space causes conflicts as well.

I'm probably not in the position to criticize, but I still feel like I have to or I will regret not having done it later.

Is it really in accordance to Ruby's design mentality to introduce new syntax just because parsing the most obvious one is too complex?

This is how I understand the issue. A new syntax is being considered because this will be hard to get working:

l = lambda { |x, y, z = (x | y)| ... }

And because block arguments don't look much (and aren't handled much like) method arguments.

If this is not only for the above two reasons, but also because you think that the above sample is hard to parse visually then please consider other choices that are more obvious than arrows pointing into random directions:

f = def(x, y, z = x | y) { ... } # also need to allow def x() { ... }
f = fun(x, y, z = x | y) { ... } # a new keyword

Personally, I think this complete situation is not as much as a problem as it might appear. -- Blocks are a special syntax in Ruby and we have all gotten used to it. It is okay for them to also have a special argument syntax. Having default arguments with the current one is not hard. We don't need both method call semantics and special block semantics both at the same time. We could get rid of Proc.new without losing anything but the danger of confusion.

Sure, the C#, Perl and ECMAScript way of doing this has advantages like being able to assign closures to variables with the same syntax as with method calls. It also allows multiple closures per method and storing them in hashes without a second syntax. Should we switch to it? Should this have been the way for Ruby to do it since the beginning?

As stated above I think switching might be more trouble than its worth. Sure, if you learn Ruby you will at one point try to do "x = { exit }", but after a small surprise you will have learnt to insert the "lambda".

Now to the more difficult part. Would it have been better if Ruby would have merged blocks and lambdas since the beginning? This is hard to answer. When I was learning Ruby I thought that it would be great to be able to supply multiple blocks to one method without needing a different syntax. Has this been a limitation? Nope, but that could be related to users of languages automatically working around issues before they encounter them.

So would there have been a downside to Ruby having unified blocks and lambdas since the beginning? Yes, I think that

10.upto(20, { |i| puts i })

is harder to type and read than

10.upto(20) { |i| puts i }

One can now argue that it does not matter for cases where there only is a block:

1.times { } is the same as 1.times({ }) anyway.

Or that we could allow trailing arguments that happen to be blocks to appear outside of the argument list:

Array.new(5) { |i| i * 2 } == Array.new(5, { |i| i * 2 })

# It is hard to come up with methods that take multiple blocks which
# isn't very surprising.
ary.context_each(
   first: { |i| puts "First: #{i}" },
   last: { |i| puts "Last: #{i}" },
) { |i| puts i }

# Or:
ary.context_each(
   first: { |i| puts "First: #{i}" },
   last: { |i| puts "Last: #{i}" },
   middle: { |i| puts i }
)

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 }

And perhaps:

printer = a -> { puts a }

And even more perhaps:

printer = a -> puts a

This is again very hard to parse. Perhaps even for humans. So:

adder = \(a, b) -> { a + b }
printer = \a -> { puts a }

Don't get me wrong here. It might be rare, but in this case I am not actually trying to talk you into changing the language. I think the best and least risky option is to just keep the current situation. I am usually for sacrificing backwards compatibility to gain more intuitiveness and simplicity, but in this case the problem is not big enough to solve it (yet?).

(7rans) #16

That's rather drastic. All it needs is a new symbol for literal hashes.
(I like [| |] myself.)

Nah, just use the _collection_ brackets for both array and hash. The
parser can tell them apart:

  # array
  [ a, b, c ]

  # hash
  [ a=>x, b=>y, c=>z ]
  [ a: x, b: y, c: z ]

Compared to this other stuff that'd be a breeze to parse.

T.

(Yukihiro Matsumoto) #17

Yes. It's among the steps lambda becoming more like real anonymous
function.

              matz.

···

In message "Re: new block notation (was: Re: ruby-dev summary 26468-26661)" on Fri, 5 Aug 2005 08:59:47 +0900, Eric Mahurin <eric_mahurin@yahoo.com> writes:

BTW, I noticed that lambdas without args now is interpreted as
no args allowed instead of any number of args allowed:

f = lambda { "xyz" };p(f["hi"])

wrong number of arguments (1 for 0) (ArgumentError)

1.8.2 allows this. Was this change intentional?

(Michel Martens) #18

I like how Trans. suggestion looks like:

10.times -> i { puts i }

10.times with i do
  puts i
end

The notation could also be supported (not required) by the 'def' construction:

def foo with bar, baz
  bar + baz
end

That way, I think it will be consistent and succinct.

Michel.

(Yukihiro Matsumoto) #19

Hi,

···

In message "Re: new block notation (was: Re: ruby-dev summary 26468-26661)" on Fri, 5 Aug 2005 09:28:15 +0900, "David A. Black" <dblack@wobblini.net> writes:

But if you had a language (and I imagine there is one somewhere :slight_smile:
that used unique strings of punctuation for all its keywords, it would
look pretty bad. Obviously that's not an issue here, but it does
suggest that there can be such a thing as too much punctuation, even
if it's unambiguous.

I agree. Too much symbols can cause memory problem. I had an
implicit assumption that there shouldn't be too much symbols.

              matz.

(Yukihiro Matsumoto) #20

Hi,

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".

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.

  * 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.

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 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.

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.

              matz.

···

In message "Re: new block notation (was: Re: ruby-dev summary 26468-26661)" on Fri, 5 Aug 2005 09:49:28 +0900, Florian Groß <florgro@gmail.com> writes: