Lexical reference to an anonymous recursive subroutine: impossible? - Perl
This is a discussion on Lexical reference to an anonymous recursive subroutine: impossible? - Perl ; Hello
It might sound slightly like a joke, but I am precisely trying to
implement the above. The reasons are as follows:
- I am programming a library function (in a module) that has a helper
function. Ideally, this helper ...
-
Lexical reference to an anonymous recursive subroutine: impossible?
Hello
It might sound slightly like a joke, but I am precisely trying to
implement the above. The reasons are as follows:
- I am programming a library function (in a module) that has a helper
function. Ideally, this helper function should be visible only to the
library function which uses it. Knowing that it is possible to say
{
my $lexical_var = 0;
sub foo {$lexical_var++;}
sub bar {print $lexical_var;}
}
to the effect is that
foo(); foo(); bar();
will print "2", but
print $lexical_var;
will yield an uninitialized variable error, I've tried to do the same
with a subroutine declaration, saying "my sub helper_function { ... ",
to learn that this is not yet implemented. As it is possible to store
a reference to an anonymous subroutine in a variable:
$helper_function = sub { ... };
and use it saying
$helper_function->(<args, if any>); # or:
&$helper_function(<args, if any>);
I've resourcefully tried to use that knowledge to implement it.
However, the fact that my helper function is recursive on top of it
all seems to be a problem: The following works:
$times = 0;
$code_ref = sub {
$times++;
print "Hello, there!\n";
$code_ref->() until ($times == 3);
};
$code_ref->(); # prints "Hello, there!" three times
but this (the line numbers are not part of the code):
1 $times = 0;
2
3 {
4
5 my $code_ref = sub {
6 $times++;
7 print "Hello, there!\n";
8 $code_ref->() until ($times == 3);
9 };
10
11 $code_ref->();
12
13 }
prints
> Hello, there!
> Undefined subroutine &main:: called at script line 8.
Thus, the anonymous subroutine referenced to in $code_ref is called
exactly once (from line 11), but apparently it cannot be found when
called from within itself (at line 8). (More precise, I assume, would
be to say "from within the subroutine, the variable is not visible",
or "it cannot be dereferenced via this variable")
The explanation that the variable $code_ref has gone out of scope
within the subroutine declaration seems to suggest itself, but I
couldn't claim that I understand this, since the declaration is within
the same block (and hence I'm anything else but confident that it is
in fact the reason).
Is there anybody who can, and would care to, explain the reasons for
this?
Thanks very much!
Florian
-
Re: Lexical reference to an anonymous recursive subroutine: impossible?
On Apr 19, 6:07 pm, florian <lor...@fsavigny.de> wrote:
> It might sound slightly like a joke, but I am precisely trying to
> implement the above. The reasons are as follows:
>
> - I am programming a library function (in a module) that has a helper
> function. Ideally, this helper function should be visible only to the
> library function which uses it. Knowing that it is possible to say
>
> {
> my $lexical_var = 0;
> sub foo {$lexical_var++;}
> sub bar {print $lexical_var;}
> }
>
> to the effect is that
>
> foo(); foo(); bar();
>
> will print "2", but
>
> print $lexical_var;
>
> will yield an uninitialized variable error, I've tried to do the same
> with a subroutine declaration, saying "my sub helper_function { ... ",
> to learn that this is not yet implemented. As it is possible to store
> a reference to an anonymous subroutine in a variable:
>
> $helper_function = sub { ... };
>
> and use it saying
>
> $helper_function->(<args, if any>); # or:
> &$helper_function(<args, if any>);
>
> I've resourcefully tried to use that knowledge to implement it.
> However, the fact that my helper function is recursive on top of it
> all seems to be a problem: The following works:
>
> $times = 0;
>
> $code_ref = sub {
> $times++;
> print "Hello, there!\n";
> $code_ref->() until ($times == 3);
> };
>
> $code_ref->(); # prints "Hello, there!" three times
>
> but this (the line numbers are not part of the code):
Please refrain from modifying your code in any way so that we can't
simply cut-n-paste.
If you need to refer to lines of your sample code in the narrative do
so by putting comments in the code and referring to those.
> 1 $times = 0;
> 2
> 3 {
> 4
> 5 my $code_ref = sub {
> 6 $times++;
> 7 print "Hello, there!\n";
> 8 $code_ref->() until ($times == 3);
> 9 };
> 10
> 11 $code_ref->();
> 12
> 13 }
>
> prints
>
> > Hello, there!
> > Undefined subroutine &main:: called at script line 8.
You forgot to use strict. Had you used strict you've had got a
different (and much more helpful) error. How much pain do you need
before you use strict?
> Thus, the anonymous subroutine referenced to in $code_ref is called
> exactly once (from line 11), but apparently it cannot be found when
> called from within itself (at line 8). (More precise, I assume, would
> be to say "from within the subroutine, the variable is not visible",
> or "it cannot be dereferenced via this variable")
Yes, the lexical variable is not in scope so you are accessing
$main::code_ref.
> The explanation that the variable $code_ref has gone out of scope
> within the subroutine declaration seems to suggest itself,
No, it's not that is has gone out of scope, but rather it hasn't come
into scope yet.
> Is there anybody who can, and would care to, explain the reasons for
> this?
Exactly the same reason as you'll get an error from
use strict;
my $foo = $foo;
The scope of a lexical variable starts at the statement following he
declaration. Within the declaration statement the lexical variable is
not yet in scope.
This is one of the few times when it actually makes sense to separate
the declaration and initialisation.
use strict; # Always!
use warnings; # Always!
my $times = 0;
{
my $code_ref;
$code_ref = sub {
$times++;
print "Hello, there!\n";
$code_ref->() until ($times == 3);
};
$code_ref->();
undef $code_ref;
}
Note the final undef. This is because you've created a circular
reference. Without the explicit undef, when the execution pointer
passes the point where the variable $code_ref goes out of scope the
closure will not get garbage collected.
Personally I don't like having to manually make sure that $code_ref
gets undef()ed on _every_ _possible_ execution path so I use a package
variable and local.
For details see my previous posts on this matter:
http://groups.google.com/group/comp....8fd05e61b50583
http://groups.google.com/group/comp....7984a52cd091ae
http://groups.google.com/group/comp....bfe18a8d5e7acd
-
Re: Lexical reference to an anonymous recursive subroutine: impossible?
On 19 Apr 2007 10:07:15 -0700, florian <lorian@fsavigny.de> wrote:
>Subject: Lexical reference to an anonymous recursive subroutine: impossible?
No, possible.
my $fib = do {
my $rec;
$rec = sub {
my $n=shift;
return +($n % 2 ? 1 : -1)*$rec->(-$n) if $n < 0;
return $n if $n < 2;
$rec->($n-1)+$rec->($n-2);
}
};
Sorry, I'm too tired ATM to read the rest of your post.
HTH,
Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
-
Re: Lexical reference to an anonymous recursive subroutine:impossible?
>>>>> "BM" == Brian McCauley <nobull67@> writes:
BM> my $times = 0;
BM> {
BM> my $code_ref;
BM> $code_ref = sub {
BM> $times++;
BM> print "Hello, there!\n";
BM> $code_ref->() until ($times == 3);
BM> };
BM> $code_ref->();
BM> undef $code_ref;
BM> }
BM> Note the final undef. This is because you've created a circular
BM> reference. Without the explicit undef, when the execution pointer
BM> passes the point where the variable $code_ref goes out of scope the
BM> closure will not get garbage collected.
that code ref should be garbage collected even without the undef as it
leaves scope. nothing outside that block refers to it so it has only one
ref count which goes to 0 upon block exit. should be very simple to test
for this by also blessing it and creating a DESTROY method to print that
it was destroyed.
uri
--
Uri Guttman ------ uri@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
-
Re: Lexical reference to an anonymous recursive subroutine: impossible?
On 19 Apr 2007 10:07:15 -0700, florian <lorian@fsavigny.de> wrote:
[...]
> but this (the line numbers are not part of the code):
>
> 1 $times = 0;
> 2
> 3 {
> 4
> 5 my $code_ref = sub {
> 6 $times++;
> 7 print "Hello, there!\n";
> 8 $code_ref->() until ($times == 3);
> 9 };
> 10
> 11 $code_ref->();
> 12
> 13 }
>
> prints
>
> > Hello, there!
> > Undefined subroutine &main:: called at script line 8.
>
> Thus, the anonymous subroutine referenced to in $code_ref is called
> exactly once (from line 11), but apparently it cannot be found when
> called from within itself (at line 8).
The way my works in this situation is rather irratating. The problem
is that my declares that $code_ref after the end of my statement. So
$code_ref isn't in scope on the RHS of the assignment.
What you wish to do is
{
my $times = 0;
my $code_ref;
$code_ref = sub {
$times++;
print "Hello, there!\n";
$code_ref->() unless ($times < 4);
}
}
-
Re: Lexical reference to an anonymous recursive subroutine: impossible?
florian wrote:
> - I am programming a library function (in a module) that has a helper
> function. Ideally, this helper function should be visible only to the
> library function which uses it. Knowing that it is possible to say
> ...
> ...
> 5 my $code_ref = sub {
> 6 $times++;
> 7 print "Hello, there!\n";
> 8 $code_ref->() until ($times == 3);
> 9 };
> 10
> 11 $code_ref->();
> ...
> > Hello, there!
> > Undefined subroutine &main:: called at script line 8.
>
> Is there anybody who can, and would care to, explain the reasons for
> this?
There have already been several correct solutions
posted, I'll only make a small addendum.
Depending on what you exactly trying to do,
you could drop the external variables and work
on the stack in your inner sub:
{
my $code_ref;
$code_ref = sub {
warn "@_\n";
push @_,-1+pop@_ and $_[1] and &$code_ref
};
$code_ref->('Hello, there!', 3);
}
This would recursively invoke the sub
and modify stack values directly, so
it can't be interfered with from outside.
Regards
M.
-
Re: Lexical reference to an anonymous recursive subroutine: impossible?
On Thu, 19 Apr 2007 22:41:54 +0200, Mirco Wahab <wahab-mail@gmx.de>
wrote:
>This would recursively invoke the sub
>and modify stack values directly, so
>it can't be interfered with from outside.
Wouldn't it be the case of magic-goto() then? (CAVEAT: I'm terribly
tired -and halfdrunk- and I didn't check if this is applicable to the
current situation.)
Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
-
Re: Lexical reference to an anonymous recursive subroutine: impossible?
On Apr 19, 10:21 pm, "David Formosa (aka ? the Platypus)"
<dform...@usyd.edu.au> wrote:
> The way my works in this situation is rather irratating. The problem
> is that my declares that $code_ref after the end of my statement. So
> $code_ref isn't in scope on the RHS of the assignment.
Oh indeed ... thanks very much for this simple explanation. Now I even
spotted the according sentence in the documentation for 'my' (Camel
Book):
A private variable is not visible until the statement /after/ its
declaration.
(i.e. not within the same statement.) I just marked that sentence in
yellow (because it is much more important than a lot of other stuff
explained there). In a sense, I have learned, a statement such as
my $var = $var + 1;
(I know - who would want to do such a thing?) must be read right side
first, something which is actually familiar, as this is the case with
all assignments, come to think of it. In
$var = $var + 1; # clumsy, generic alternative to $var++;
the expression $var + 1 is evaluated _first_, and _then_ the result is
assigned to $var.
Thanks very much!
Florian
-
Re: Lexical reference to an anonymous recursive subroutine: impossible?
On Apr 19, 9:08 pm, Uri Guttman <u...@stemsystems.com> wrote:
> >>>>> "BM" == Brian McCauley <nobul...@> writes:
>
> BM> my $times = 0;
> BM> {
>
> BM> my $code_ref;
> BM> $code_ref = sub {
> BM> $times++;
> BM> print "Hello, there!\n";
> BM> $code_ref->() until ($times == 3);
> BM> };
>
> BM> $code_ref->();
> BM> undef $code_ref;
> BM> }
>
> BM> Note the final undef. This is because you've created a circular
> BM> reference. Without the explicit undef, when the execution pointer
> BM> passes the point where the variable $code_ref goes out of scope the
> BM> closure will not get garbage collected.
>
> that code ref should be garbage collected even without the undef as it
> leaves scope. nothing outside that block refers to it so it has only one
> ref count which goes to 0 upon block exit. should be very simple to test
> for this by also blessing it and creating a DESTROY method to print that
> it was destroyed.
Please see the previous thread (2nd one referenced in my post) where
you asserted exactly the same thing. You were wrong then (and you
admitted it). You're wrong again.
-
Re: Lexical reference to an anonymous recursive subroutine: impossible?
On Apr 19, 7:42 pm, Brian McCauley <nobul...@> wrote:
> You forgot to use strict. Had you used strict you've had got a
> different (and much more helpful) error. How much pain do you need
> before you use strict?
Hmm ...
> Exactly the same reason as you'll get an error from
>
> use strict;
> my $foo = $foo;
Frankly, I wouldn't have seen the similarity without knowing. But
you're probably right with using strict. I tried this out on my
example, and
use strict;
use warnings;
$main::times = 0;
{
my $code_ref = sub {
$main::times++;
print "Hello, there!\n";
$code_ref->() until ($main::times == 3); # (line 12)
};
$code_ref->();
}
yielded the error
Global symbol "$code_ref" requires explicit package name at script
line 12.
which, in fact, tells me that $code_ref in this line is not the
lexical one, while the one in line 15 apparently is. (Not at the very
first glance, but on second look, yes.)
> Note the final undef. This is because you've created a circular
> reference. Without the explicit undef, when the execution pointer
> passes the point where the variable $code_ref goes out of scope the
> closure will not get garbage collected.
> For details see my previous posts on this matter: ...
I've looked into these, and also read the discussion about garbage
collection in this thread. The Camel Book seems to confirm what you
say, but I'm actually rather confused about this, as I'm not advanced
enough (in particular, I've shunned OO and some related stuff so far)
to follow the discussions. But if I've understood the book correctly,
the lexical variable references the anonymous subroutine, while
something inside the subroutine references the variable in turn, which
is why their 'internal reference counts' (whatever that may be) can
never go to zero, even though they go out of scope when the block is
left. I also understand why undef-ing the variable should break this
circle, so I'll do this. Thanks very much for pointing this out!
> Personally I don't like having to manually make sure that $code_ref
> gets undef()ed on _every_ _possible_ execution path so I use a package
> variable and local.
Where I intend to apply it it is never invoked casually but only
inside a certain block in the module file, so it should not be a
problem, I think. (That was actually the point - making it private to
one function.) I know I could have achieved a comparable effect by
using an ordinary subroutine, using Exporter and disallowing to export
the subroutine, which would have restricted it to the module file, but
this seems even more compelling.
Thanks very much for your help!
Florian
Similar Threads
-
By Application Development in forum Perl
Replies: 0
Last Post: 11-24-2007, 03:03 AM
-
By Application Development in forum Perl
Replies: 0
Last Post: 09-08-2007, 08:03 AM
-
By Application Development in forum Perl
Replies: 0
Last Post: 07-06-2007, 02:03 PM
-
By Application Development in forum Perl
Replies: 0
Last Post: 02-18-2005, 12:39 PM
-
By Application Development in forum Perl
Replies: 3
Last Post: 01-30-2004, 10:40 AM