Closures with $_?

M

Michele Dondi

The documentation is clear (and I'm not contending this!) about the
fact that closures are about *lexical* variables.

Thus I *do* understand why the following doesn't work as (I, for one,
could have) expected:

# perl -le 'print map $_->(), map { sub { $_ } } qw/f o o/'
CODE(0x8137f84)CODE(0x8137f84)CODE(0x8137f84)

BTW: OTOH I do *not* understand *how* exactly it fails to work, i.e.
what I actually get. Data::Dumper on

map { sub { $_ } } ...

gives me

$VAR1 = sub { "DUMMY" };
$VAR2 = $VAR1;
$VAR3 = $VAR1;

As a side note indeed this is *not* WIM...

However, to return to the main theme, using

map { my $t=$_; sub { $t } } qw/f o o/

instead does exactly what I want, again as of the documentation. But
IMHO the latter conveys the psychological feeling of being equivalent
to the former, just in a more clumsy form.

So I wonder wether, apart possible technical difficulties, there are
other issues against the possibility of having closures using $_.


Michele
 
C

ctcgag

Michele Dondi said:
The documentation is clear (and I'm not contending this!) about the
fact that closures are about *lexical* variables.

Thus I *do* understand why the following doesn't work as (I, for one,
could have) expected:

# perl -le 'print map $_->(), map { sub { $_ } } qw/f o o/'
CODE(0x8137f84)CODE(0x8137f84)CODE(0x8137f84)

BTW: OTOH I do *not* understand *how* exactly it fails to work, i.e.
what I actually get.

at the time of the outer map, $_ contains a code ref to a subroutine
which returns $_. So $_->() just returns the value of $_,
which of course is a code ref and stringifies to look like that.
I am kind of surprised it is the *same* coderef each time, but I guess
I shouldn't be surprised. Since code cannot be changed, but only replaced,
coderefs are essentially immutable and there is no reason not to put all
copies at the same address.

Data::Dumper on

map { sub { $_ } } ...

gives me

$VAR1 = sub { "DUMMY" };
$VAR2 = $VAR1;
$VAR3 = $VAR1;

As a side note indeed this is *not* WIM...

What about it is not what you meant? The "DUMMY" thing is just
there as an artifact of Data::Dumper (perldoc Data::Dumper, search
for DUMMY). The fact that Data::Dumper shows $VAR2=$VAR1 means
that the reference objects don't just happen to be identical, but
rather that they are identical because they share the same underlying
storage.
However, to return to the main theme, using

map { my $t=$_; sub { $t } } qw/f o o/

instead does exactly what I want, again as of the documentation.

Did you run Data::Dumper on that as well?
But
IMHO the latter conveys the psychological feeling of being equivalent
to the former, just in a more clumsy form.

So I wonder wether, apart possible technical difficulties, there are
other issues against the possibility of having closures using $_.

I don't understand what you include in "possible technical difficulties",
and therefore don't know what issues there are other than the ones you
already include.

Xho
 
M

Michele Dondi

at the time of the outer map, $_ contains a code ref to a subroutine
which returns $_. So $_->() just returns the value of $_,
which of course is a code ref and stringifies to look like that.
OK!!


What about it is not what you meant? The "DUMMY" thing is just
there as an artifact of Data::Dumper (perldoc Data::Dumper, search

I *do* know that.

Sorry, I reread my post and I realize that definitely I wasn't clear.
More precisely I could have avoided this thing with Data::Dumper at
all: I was just trying to say in yet another way that it seems logical
to me one could expect three anonymous subs each represented by a line
like the first one above.
Did you run Data::Dumper on that as well?

You bet I did!
I don't understand what you include in "possible technical difficulties",
and therefore don't know what issues there are other than the ones you
already include.

I have not included any technical difficulty, just *evidence* that
closures are supported only as far as lexical variables are concerned.
But I don't know why, because I don't know perl internals. So in
"possible technical difficulties" I include *any* reason p5p's may
give for e.g.

map { sub { $_ } } qw/f o o/;

not being equivalent to (the clumsier)

map { my $t=$_; sub { $t } } qw/f o o/;


Michele
 
B

Ben Morrow

Quoth Michele Dondi said:
So I wonder wether, apart possible technical difficulties, there are
other issues against the possibility of having closures using $_.

A closure has to use lexical variables (only), because it relies on the
closure being called *after the variables it closes on have gone out of
(normal) scope*. Globals don't need closures: they are always in scope
anyway. Consider:

{
my $x = 4;
sub foo {
my $y = $x;
$x = shift;
return $y;
}
}

foo 3;

When foo is called, it can get at the lexical $x *even though it has
gone out of scope*, because it is a closure. If $x was a global, there
would be no need for closure: $x is always available from anywhere.

You are perhaps not thinking of this sub foo as a closure; it is,
however. The situation you probably have in mind:

my @a;
for my $x (1..4) {
push @a, sub { $x };
}
print map $_->(), @a;

is slightly more complicated because the scope that is the 'for' loop
runs four times, and each one is *a completely separate scope* from the
others. That is, there are four different variables named '$x' which do
not affect one another, just as there are two here:

{
$x = 1;
}
{
print $x;
}

..

So (and I apologise if you actually understood all this already, but I
got the impression from your example that you didn't), you question is
not 'can closures be made to close on $_' but rather 'can $_ be made
lexical'. The answer to that is that it could except it would break
programs expecting it to be global, so it won't happen till Perl6 (where
$_ is, indeed, lexical, and thus closed upon by closures).

Ben
 
J

Joe Smith

Michele said:
I have not included any technical difficulty, just *evidence* that
closures are supported only as far as lexical variables are concerned.
But I don't know why, because I don't know perl internals.

Closures require at least one lexical variable.
Otherwise it would not be able to distinguish one closure from another.

Just accept the restriction that closures need lexical variables and
move on.
-Joe
 
C

ctcgag

Michele Dondi said:
I have not included any technical difficulty, just *evidence* that
closures are supported only as far as lexical variables are concerned.

Maybe I'm overstepping my knowledge, or getting bogged down in semantics,
but I would say that closures are supported for all variables. It is just
that closures are kind of trivial when they don't include any lexical
variables.

But I don't know why, because I don't know perl internals. So in
"possible technical difficulties" I include *any* reason p5p's may
give for e.g.

map { sub { $_ } } qw/f o o/;

Here, $_ is the same variable each time the sub is defined, so all
three subs are effectively equivalent. (The perl implementation is
smart enough to realize this, and makes them exactly equivalent, not
just effectively equivalent; but that is just an optimization, not
a fundamental difference).

The problem you were having is that you kept overwriting the value of
$_ between the time the sub was defined and the time it was used.
not being equivalent to (the clumsier)

map { my $t=$_; sub { $t } } qw/f o o/;

Here, $t is a different variable each time the sub is defined, so each of
the resultant closures are different. Each one contains a (different)
internal reference to a (different) now-anonymous variable, formerly known
as $t.

The fact that the closure contains a reference to the variables formerly
known as $t keeps the ref counts above zero, so those variables can't
disappear as long as the closures themselves are around. (This point is
irrelevant to package variables, since they don't disappear anyway until
the end of the program anyway.) Furthermore, the closures' references are
the only references to those variables, once you leave the scope of the map
block, so the variables are unlikely to get stepped on like $_ was.


If you change the code just a bit by taking the "my" out of the loop:

my $t;
print map {$_->()} map { $t=$_; sub { $t } } qw/f o o/;

Now, each closures refers to the same $t, just as like in your first case
they all refer to the same $_. All of the subs are effectively equivalent
(but the perl implementation doesn't realize this, so each coderef has a
different address). And that one variable $t gets walked all over, but not
as badly as $_ did in the first example.

to make it even more like the first example:

my $t;
print map {$t=$_; $_->()} map { $t=$_; sub { $t } } qw/f o o/;


Xho
 
M

Michele Dondi

Maybe I'm overstepping my knowledge, or getting bogged down in semantics,
but I would say that closures are supported for all variables. It is just
that closures are kind of trivial when they don't include any lexical
variables.

This is what I meant.

[lengthy explanation snipped]

TY for the explanation.


Michele
 
M

Michele Dondi

So (and I apologise if you actually understood all this already, but I

I'd say that I "sort of" understood all this in the sense that (IMHO)
I already knew all this much better than I may have given the
impression of. Said this, other posters already made the point and
clarified things up, so in some sense yes: your explanation was
redundant. But you know: repetita iuvant! And all this may be helpful
for others too.
got the impression from your example that you didn't), you question is
not 'can closures be made to close on $_' but rather 'can $_ be made
lexical'. The answer to that is that it could except it would break
programs expecting it to be global, so it won't happen till Perl6 (where

Indeed I'm aware that hoping for $_ to be made lexical would be too
much. And to be fair I wouldn't regard it as a Good Thing(TM), from a
Perl5's perspective.

Rather I wonder wether, apart possible technical difficulties (as of
my OP), it would be possible to add still some more magic to $_ in
order to make it behave like it were a lexical var in all those
situations in which something is automatically aliased to it (i.e.
C<for>, C<map>, etc.)

After all

map { "\$_=<$_>" } @input;

and

map { my $t=$_; "\$_=<$t>" } @input;

are perfectly equivalent, so I *think* that one could reasonably
wonder why

map { sub { $_ } } @input;

and

map { my $t=$_; sub { $t } } @input;

are not. Then the answer, as you all have been explaining and
stressing, is that (to sum up as briefly as possible) "a sub is not a
string, period". But then there are situations when one would want to
achieve the effect of the second example while I can't see any actual
use for the first. So IMHO it would be a big, typically perlish
dwimmery to have the first one behave like the second one.


Thanks,
Michele
 

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,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top