Anonymous methods, blocks etc. (Cont. 'default block params')

E

ES

Listening in on the Roundtable (thanks to the brave recording crew and
Ezra Zygmuntowicz), it seems as if we were somewhat sidetracked in the
'default block parameters' discussion; the -> notation is to specifically
allow anonymous methods and the block syntax would still be allowed for,
well, blocks.

Multiple assignment was also mentioned; I am not quite sure how this plays
in, perhaps someone could clarify on that. (I always assume it is the
difference between a, b, c = 1, 2, 3 vs. a, b, c = [1,2,3].)

So here are some points I have pondered.

1. Blocks vs. Procs. I think the desire has long been to make any
differences between these two (and also Proc.new vs. Kernel.proc)
disappear.

2. Blocks/Procs versus anonymous methods. Should these be actually
*different* or should

3. Anonymous methods vs. methods. More aptly, should methods just be
special instances of anonymous methods in that they are tied to
a particular class?

4. Methods vs. Procs. Should these two be different beasts or can
the differences be implemented with context rather than content?


Now, based on my cursory YACC knowledge (and much input from a gentleman
on #ruby-lang), all these would be possible to implement with varying degrees
of difficulty. Even using the traditional block syntax with default arguments
would be

# 1. New syntax, 'easy' to implement
anon = -> (x = 'Hello') { puts x }

# 2. Also 'new' syntax though using def for this
# would require changes in, well, 'def'.
anon = def(x = 'Hello') { puts x }

# 3. Using 'lambda' (or something else) would be simpler than above.
anon = lambda(x = 'Hello') { puts x }

# 4. Implicit conversion is possible with = not being a method.
anon = {|x = 'Hello'| puts x }

# 5. The 'traditional' style.
anon = lambda {|x = 'Hello'| puts x } # Sub 'lambda' with 'def'

# 6. More? The : or . seems not necessary in this context of blocks?


Personally I would like to see the complete unification of Blocks, Anons
and Methods with the Block being the basic element of which the two others
are merely contextually created special cases; this combined with either
the def/lambda() syntax or the plain block syntax (#4 above).

Er, well, yeah. Just felt the urge to write something :)

E
 
R

robertj

hi,

are there any non obvious issue why blocks, anonymous methods and
methods could or should not be unified?

i find it very ugly that i have to call a proc like this
aproc.call or aproc[] instead of aproc(). unification of all those
constructs would be really great.

btw will be possible to get a handle on a instance method in ruby
1.9/2.0

something like this:
aproc = &anInstance.method

and then of course
aproc()

ciao robertj
 
W

Wilson Bilkovich

I agree. It seems to me that once Ruby has 'real deal' anonymous
methods, then that's a primitive that could be used to implement the
other constructs, like Proc.

Also, I've been trying not to comment on the arrow thing, but my
biggest complaint is this:
In functional notation, an 'f arrow x' means apply the f function to
the x argument. The example Ruby syntax is reversing that, and using
the arrow for specifying a function, rather than using it.

--Wilson.
 
E

ES

Wilson said:
I agree. It seems to me that once Ruby has 'real deal' anonymous
methods, then that's a primitive that could be used to implement the
other constructs, like Proc.

The hurdle for this, I assume (apart from having to rewrite a lot of
code and another important thing addressed below), is that the closure
feature does not play nice with the current semantics:

# Pseudosyntax to clarify
class Foo
@quux = 42

def :foo {|x, y, z|
do_something_with x, y, z
}

def :do_something {...}
end

The closure would grab the environment; @quux would be available and
the implicit 'self' would refer to the Class object, not the instance.
This means that all messages to a given object would invoke some sort
of an #instance_eval on the method's code.

(Please correct me and voice other *technical* issues if any!)

These are by no means unsurmountable but there is quite a bit of work
involved in rewriting.

One big thing, though: one may wish to intentionally make a distinction
between a 'behaviour' of an object and a 'function' which these anons
(and to an extent Procs) can be seen as. I have made my peace by just
thinking of this as a different way of defining those behaviours (it is
not like they actually spawn to life by themselves now) but I can, sort
of, see how the thought might seem unappealing.
Also, I've been trying not to comment on the arrow thing, but my
biggest complaint is this:
In functional notation, an 'f arrow x' means apply the f function to
the x argument. The example Ruby syntax is reversing that, and using
the arrow for specifying a function, rather than using it.

--Wilson.

hi,

are there any non obvious issue why blocks, anonymous methods and
methods could or should not be unified?

i find it very ugly that i have to call a proc like this
aproc.call or aproc[] instead of aproc(). unification of all those
constructs would be really great.

btw will be possible to get a handle on a instance method in ruby
1.9/2.0

something like this:
aproc = &anInstance.method

and then of course
aproc()

ciao robertj

E
 
S

Sean O'Halpin

2. Blocks/Procs versus anonymous methods. Should these be actually
*different*

Short answer - yes. An anonymous function would mean you're not
carrying around a whole heap of baggage when no closure is required
and gives you a clean scope to help prevent accidental aliasing
errors.

In general, I would expect to use an anonymous function unless I
specifically required the extra features of a closure. Ruby makes it
so easy to use closures that I suspect many people don't realise the
consequences of using such a powerful construct.

Regards,

Sean
 
A

Austin Ziegler

Short answer - yes. An anonymous function would mean you're not
carrying around a whole heap of baggage when no closure is required
and gives you a clean scope to help prevent accidental aliasing
errors.

Except that Matz still plans on making anonymous functions have closure
capabilities. This is why, after Dave Thomas suggested:

anon =3D def(x =3D 5)
# implementation of anon
end

I then suggested:

anon =3D lambda(x =3D 5)
# implementation of anon
end

To me, this is clearer than any of the other options that have been so
far suggested for anonymous functions. I don't know that I'll be using
anonymous functions for most of what I do in Ruby, but I can see the
point of them and how they *are* subtly different than blocks. I just
don't particularly care for the proposed syntax:

anon =3D ->(x =3D 5) { ... }

-austin
 
T

Trans

Austin said:
Except that Matz still plans on making anonymous functions have closure
capabilities. This is why, after Dave Thomas suggested:

anon = def(x = 5)
# implementation of anon
end

I then suggested:

anon = lambda(x = 5)
# implementation of anon
end

I agree that a *true* anonymous function is needed, but also think it
would be nice if one could selectively "pull down" elements of closure
somehow.

Alos, there are other places in which non-closure can be helpful, such
a Class.new{ }, so, please, we should not restrict this to functions.

It has been suggestd before that using 'do...end' not provide closure
while '{...}' would, but this has some issues, not the least of which
is back(ward-compatability)-breaking. But perhaps if parenthesis were
used on the 'do'?

lambda do |x|
# ... has closure
end

lambda do(x)
# ... does not have closure
end

Just a thought.

T.
 
S

Sean O'Halpin

Except that Matz still plans on making anonymous functions have closure
capabilities.
Hmmm. I must have missed that. What does "closure capabilities" mean exactl=
y?
This is why, after Dave Thomas suggested:

anon =3D def(x =3D 5)
# implementation of anon
end

I then suggested:

anon =3D lambda(x =3D 5)
# implementation of anon
end

To me, this is clearer than any of the other options that have been so
far suggested for anonymous functions.

I was under the impression that it was

anon =3D def(x =3D 5) ... end

for def style semantics (i.e. 'true' anonymous function, opaque scope, etc.=
) and

block =3D lambda(x =3D 5) ... end

for closures. If so, then I would endorse these suggestions.

Otherwise, I have to confess, I'm a little confused as to what the
proposal for anonymous functions actually means.

Regards,

Sean
 
S

Sean O'Halpin

I agree that a *true* anonymous function is needed,

I'm surprised more people don't seem to think real anonymous functions
would be useful. I'm pretty sure they'd be applicable in the majority
of cases where we use blocks now, especially with map, inject, select,
grep, etc. They would surely be more efficient (no need to set up
binding, no lookup outside current scope, lower memory usage).
but also think it
would be nice if one could selectively "pull down" elements of closure
somehow.

What do you mean by 'elements of closure'?
lambda do |x|
# ... has closure
end

lambda do(x)
# ... does not have closure
end

I quite like that. While we're at it, how about

lambda {|x| .. }

for closure and

lambda [|x| ... ]

for anonymous functions (on analogy with hashes vs arrays, i.e. more
complex vs simpler).

However, the absence of this as an option makes me think it has
already been suggested and shot down.

Regards,

Sean
 
A

Austin Ziegler

Hmmm. I must have missed that. What does "closure capabilities" mean
exactly?

Keeps local scope at the time that the closure is created.
I was under the impression that it was

anon =3D def(x =3D 5) ... end

for def style semantics (i.e. 'true' anonymous function, opaque scope,
etc.) and

block =3D lambda(x =3D 5) ... end

for closures. If so, then I would endorse these suggestions.

This is not what was discussed on Friday during the roundtable or on
Saturday during the keynote. Both were suggested to solve the same
problem -- that is, the same problem that is currently solved in 1.9
with:

anon =3D ->(x =3D 5) { ... }

I think that a *lot* of people really don't like that notation. Too many
symbols, lack of a left-side for the arrow, etc. But my sense of the
room was that either using def() or lambda() was generally felt to be
cleaner and as meaningful. Using def(), however, means that "def" is
contextually closure/non-closure depending on the presence of a name. It
also seemed to me that Matz wasn't fond of the reuse of "def".
Otherwise, I have to confess, I'm a little confused as to what the
proposal for anonymous functions actually means.

There is a difference between anonymous functions (lambdas) and blocks
in that blocks are considered -- after a fashion -- to be an extension
of the using/calling method. So parameters are passed to blocks in
parallel-assignment fashion and are passed to lambdas as actual
parameter lists. Also, "return" in a block will return from the yielding
function; in a lambda, it will return from the lambda only.

I'm surprised more people don't seem to think real anonymous functions
would be useful. I'm pretty sure they'd be applicable in the majority
of cases where we use blocks now, especially with map, inject, select,
grep, etc. They would surely be more efficient (no need to set up
binding, no lookup outside current scope, lower memory usage).

I have yet to need one (an anonymous function). I personally don't
believe that it would necessarily be more efficient, either. Indeed,
with my use of #map, etc., I tend to liberally use the fact that no new
scope is introduced and that the block is a closure. I think that your
estimation of which would be more useful flies contrary to current use
and likely continued future use of Ruby.

Indeed, I don't think that I'd ever use the lambda() keyword that has
been proposed to replace ->() in 1.9. I could be wrong, but that's just
not my programming style. I almost certainly wouldn't use one that gives
me an anonymous non-closure function. I don't think that that's an
important enough use case, where a named method would work just as well.

Others may find it more useful, but I haven't had a need yet.

[...]
I quite like that. While we're at it, how about

I can't stand it. It's entirely too contextual and "magic". If you
really *must* have non-closure anonymous functions, propose a keyword.
Magic punctuation doesn't do it for me. IMO, there's just a little too
much magic punctuation in Ruby as it stands now. (Not much, but I'm not
really comfortable with **kwargs.)
lambda {|x| .. }

for closure and

lambda [|x| ... ]

No. That's even uglier than the first.

-austin
 
S

Sean O'Halpin

There is a difference between anonymous functions (lambdas) and blocks
in that blocks are considered -- after a fashion -- to be an extension
of the using/calling method.

I see that there is a difference in what either of us means by an
"anonymous function".

I mean something like the body of a def method without a name - what
you get when you use the method() function (i.e. opaque scope, no
closure) - you mean lambda (i.e. closure).
I personally don't believe that it would necessarily be more efficient

Yes, I hadn't thought of the cost of setting up a new scope (silly
considering that is one of the main reasons I would like to see
anonymous functions). I guess the only real way to find out would be
to try it.
It also seemed to me that Matz wasn't fond of the reuse of "def".

Shame - I thought the lambda/def distinction was a good one.
lambda [|x| ... ]

No. That's even uglier than the first.

Ah well. Different eyes I guess :)

Sean
 
T

Trans

Austin said:
This is not what was discussed on Friday during the roundtable or on
Saturday during the keynote. Both were suggested to solve the same
problem -- that is, the same problem that is currently solved in 1.9
with:

anon = ->(x = 5) { ... }

I think that a *lot* of people really don't like that notation. Too many
symbols, lack of a left-side for the arrow, etc. But my sense of the
room was that either using def() or lambda() was generally felt to be
cleaner and as meaningful. Using def(), however, means that "def" is
contextually closure/non-closure depending on the presence of a name. It
also seemed to me that Matz wasn't fond of the reuse of "def".

I would have to agree with matz actually.
I have yet to need one (an anonymous function). I personally don't
believe that it would necessarily be more efficient, either. Indeed,
with my use of #map, etc., I tend to liberally use the fact that no new
scope is introduced and that the block is a closure. I think that your
estimation of which would be more useful flies contrary to current use
and likely continued future use of Ruby.

Indeed, I don't think that I'd ever use the lambda() keyword that has
been proposed to replace ->() in 1.9. I could be wrong, but that's just
not my programming style. I almost certainly wouldn't use one that gives
me an anonymous non-closure function. I don't think that that's an
important enough use case, where a named method would work just as well.

Others may find it more useful, but I haven't had a need yet.

In many cases I don't think it would matter which was used. So if
non-closure is at all more efficient that's agood thing. Either way I
have come across situations where I NEED non-closure, but there is
currently no reasonable way to do it.
[...]
I quite like that. While we're at it, how about

I can't stand it. It's entirely too contextual and "magic". If you
really *must* have non-closure anonymous functions, propose a keyword.
Magic punctuation doesn't do it for me. IMO, there's just a little too
much magic punctuation in Ruby as it stands now. (Not much, but I'm not
really comfortable with **kwargs.)

I agree with you on both accounts. I don;' think it's a good idea, but
perhaps it might stimulate some better ideas. And I concur **kwargs is
stinky.
lambda {|x| .. }

for closure and

lambda [|x| ... ]

No. That's even uglier than the first.

When you consider all the other proposals, this really stands out as
the *least* ugly way it could be done, and have suggested it too.
Unfortuantely it has one major problem. It is ambigious with #[]
method. To overcome you'd either have to always use a space before the
block or always incldue the bars ||. Both suck. Of course with Matz'
perly notation,

->(x=4)[ ... ]

That problem goes away too ;)

T.
 
D

Daniel Schierbeck

Sean said:
Shame - I thought the lambda/def distinction was a good one.

Why not use lambda/function?

func = function(x, y = 1) { do_something(x, y) }


Cheers,
Daniel
 
E

ES

Daniel said:
Why not use lambda/function?

func = function(x, y = 1) { do_something(x, y) }

I originally suggested

anon = lambda(foo = 'bar') {...}

-or-

anon = lambda(foo = 'bar') {|foo| ...}

...and it seems it still is the least offensive variation out
there to most people. I am not quite sure I like (Austin's?)
version from the roundtable:

anon = lambda(foo = 'bar')
...
end

I think mine was better ;) I suppose this would indicate the
'special' nature better but I prefer the dovetailing to current
syntax.
Cheers,
Daniel

E
 
T

Trans

func = function(x, y = 1) { do_something(x, y) }

Let me try to convey this once more: the closure issue is not simply a
matter of anonymous function. It is applicable to _any_ block.

T.
 
E

Eric Mahurin

--- Trans said:
I agree that a *true* anonymous function is needed, but also
think it
would be nice if one could selectively "pull down" elements
of closure
somehow.

v1.9 already has the ability to do the opposite which kind of
allows you to get the same effect. You can explicitly tell it
what variables are local to the block by putting them after the
arguments and a ";". Matz described it on a previous thread or
maybe it was this one when it was "default block params".

If Matz optimizes out all of the unused variables out of the
closure (he mentioned doing it after "eval" becomes a keyword)
and you use the above ;-specified local variables, maybe you
don't need non-closure blocks/lambdas. But, I kind of still
wish we had a syntax where the variables in a block/lambda were
local (non-closure) by default.



=09
=09
__________________________________=20
Yahoo! Mail - PC Magazine Editors' Choice 2005=20
http://mail.yahoo.com
 
S

Sean O'Halpin

lambda [|x| ... ]

No. That's even uglier than the first.

When you consider all the other proposals, this really stands out as
the *least* ugly way it could be done, and have suggested it too.

Well, I'm glad ~someone~ likes it :)
Unfortuantely it has one major problem. It is ambigious with #[]
method.

I see. So these would be ok:

(1..10).map[|x| x * x]
(1..10).map [|x| x * x]

but this is ambiguous:

(1..10).each[ puts "Hello" ]

OK - I see that - it conflicts with the :[] method, as in:

(1..10).to_a[ 1 ]
To overcome you'd either have to always use a space before the
block or always incldue the bars ||. Both suck.

So either
(1..10).each[|| puts "Hello" ]
(1..10).each [|| puts "Hello" ]
or
(1..10).each [ puts "Hello" ]

I doubt that a space is sufficient to disambiguate it from an array
parameter, e.g. in

(1..10).my_each [ puts "Hello" ]

class Range
def my_each(*args, &block)
#...args =3D [ puts "Hello" ] or block =3D [ puts "Hello" ]?
end
end

So that knocks that on the head. And I recall a certain amount of
apoplexy regarding the double bars. Best not stir up that nest of
hornets again ;)
Of course with Matz'
perly notation,

->(x=3D4)[ ... ]

That problem goes away too ;)

T.

If only it were that easy!

Regards,

Sean
 
S

Sean O'Halpin

But, I kind of still
wish we had a syntax where the variables in a block/lambda were
local (non-closure) by default.

Maybe if we say it often enough? ;)

Sean
 
A

Austin Ziegler

Maybe if we say it often enough? ;)

Doubtful. I think to convince matz, real examples would need to be
presented (as an RCR!) as to why this is necessary. IANM, but IMO
theoretical need and wish ain't sufficient.

-austin
 
T

Trans

Austin said:
Doubtful. I think to convince matz, real examples would need to be
presented (as an RCR!) as to why this is necessary. IANM, but IMO
theoretical need and wish ain't sufficient.

The easist is the old gotcha. Programmer has code (doesn't much matter
what it is)

class X
def foo
l = lambda { |a| x = a**2; x + 1 }
return l[1],l[2]
end
end

class Y
def bar( n )
x = n * 3
return x
end

And wants to resue the lambda so uses old fashion copy and paste:

class Y
def bar( n )
x = n * 3
l = lambda { |a| x = a**2; x + 1 }
return x + l[3]
end
end

Oopsy.

For something a little more concrete:

class X
def x ; 1;end
end
=> nil

class Y < X
class X
def x;2;end
end
def x;3;end
end
=> nil

X.new.x
=> 1
Y.new.x
=> 3
Y::X.new.x
=> 2

Now try:

class X
def x;1;end
end
=> nil

Y = Class.new(X) do
X = Class.new do
def x;2;end
end
def x;3;end
end
(irb):5: warning: already initialized constant X
=> Y

X.new.x
=> 2
Y.new.x
=> 3
Y::X.new.x
(irb):12: warning: toplevel constant X referenced by Y::X
=> 2

T.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top