Re: how to declare a local *subname=sub{}?
by LanX (Saint) on Oct 30, 2016 at 22:35 UTC
|
> So why does the "local *bsub" have no effect and why does the inclusion of "local *asub" prevent it from being callable in "stuff", below?
local is a runtime command which restores at the end of the scope, given by the block markers here.
And the declaration of subs is a compile-time effect.
Obviously you are calling stuff after the restoration.
HTH your code and intentions are not very clear, this smells like a XY problem
Update:
If you want to manipulate (so called monkey patching ) which routines are called within a sub,
you have to manipulate the symbol table right before calling the surrounding sub.
That is
stuff(); #original
{
local *asub = $code_ref;
stuff(); # new behavior local (sic) only
}
stuff(); #original
update
But you don't need local if you don't need it to be restored.
I'd rather suspect you might want to look into closures and how to call lexical coderefs
| [reply] [Watch: Dir/Any] [d/l] |
|
Possibly because 1 question expanded into 2?
1) Why does including the "local *asub" prevent it from being called in "stuff"? I.e. if you uncomment the "local *asub" line, it can't be called in "stuff" -- this is the main question.
2) Why does including the "local *bsub" (of an interior function -- different animal) appear to be ignored in "sub stuff".
In playing w/the test case, I noted that I could put the "local *'subname', outside
of an interior sub where it is implemented -- but that doing so was "ignored", from-the-standpoint of trying to call it from "outside" its containing sub (i.e. the attempted call to &bsub in "stuff()". That curiosity created question#2...
Note, I wouldn't expect calling an interior function (as stuff tries to call bsub) to necessarily work -- just that I found that trying to pre-declare it with local didn't even change the error message when "stuff" tried to call it. I thought that was strange.
Main Q is why or how might I _declare_ asub, or is
*asub = sub{...} equivalent to
sub asub {}?
It's that I'm not used to seeing an undeclared name on the LeftHandSide without it being flagged by "strict" as it not being declared.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
|
|
> Main Q is why or how might I declare asub, or is
*asub = sub{...} equivalent to
sub asub {}
Almost equivalent, the prior has a runtime effect the latter only compile time.
See perlmod for phases of execution and do some experiments checking the availability of subs.
But I'm repeating myself now. ...
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
1) because local restores the (here undef) value of the code slot of *asub at the end of the scope, which is reached before stuff() is called.
| [reply] [Watch: Dir/Any] [d/l] |
|
|
|
> Possibly because 1 question expanded into 2?
Please see How (Not) To Ask A Question
Though my answers include many valuable informations, this thread will be of no help for the majority, because your intentions are unclear and your code mangled
| [reply] [Watch: Dir/Any] |
Re: how to declare a local *subname=sub{}?
by haukex (Archbishop) on Oct 31, 2016 at 09:39 UTC
|
Hi perl-diddler,
Although LanX has already explained several things in various posts, one keyword that has not been named in this thread is dynamic scope, personally I find this easiest to remember. local only affects things in the current dynamic scope - as explained in Temporary Values via local(), it changes the value of a global at runtime, which will also affect any functions called at runtime in the scope where local is in effect, but at the end of the scope, the previous value of the variable is restored. An example:
our $foo = "foo";
{
local $foo = "bar";
sub quz {
print "\$foo = $foo\n";
}
}
quz(); # prints "$foo = foo"
Once you realize what local is doing, you'll see that the above code is basically equivalent to this:
our $foo = "foo";
{
$foo = "bar";
sub quz {
print "\$foo = $foo\n";
}
$foo = "foo";
}
quz(); # prints "$foo = foo"
Note how quz is called after after the original value of $foo is restored. So I hope that explains why your local *asub = sub ... would cease to have any effect once Perl has completed executing your block { package Do::Stuff; ... }.
Your use of *bsub warrants some closer inspection though. In your code example, if you call $p->stuff after $p->do_internal_sub, suddenly the call the bsub works! It's a bit complicated, but if you keep in mind the distinction as to when which line is executed, it makes sense. I'll explain using this example:
#!/usr/bin/env perl
use warnings;
use strict;
sub foo { print "orig foo\n" }
sub bar { print "orig bar\n" }
{
local *foo = sub { print "local foo\n"; };
local *bar;
sub quz {
foo();
eval { bar(); 1 } or warn "calling bar failed: $@";
}
sub baz {
*bar = sub { print "local bar\n"; };
}
quz(); # first call to quz
baz(); # first call to baz
quz(); # second call to quz
}
quz(); # third call to quz
baz(); # second call to baz
quz(); # fourth call to quz
__END__
Subroutine main::foo redefined at local_ex.pl line 8.
local foo
calling bar failed: Undefined subroutine &main::bar called at local_ex
+.pl line 12.
local foo
local bar
orig foo
orig bar
Subroutine main::bar redefined at local_ex.pl line 15.
orig foo
local bar
- When local *bar; is executed, its value is cleared (Update: this is the intended effect of local, although the documentation is admittedly a little hard to find). Thus, the first call of quz();, while the local *bar; is still in effect and baz has not been executed, will not have a sub bar to execute.
- Then, we call baz();, which assigns a value to the currently still localized bar, so the second call of quz(); prints the two "local ..." strings.
- Once the block is exited, the effect of local ends and the original definitions of foo and bar are restored, so the third call to quz(); prints the two "orig ..." strings.
- Then we call baz(); a second time, which redefines bar. Now what's important to remember here is that the effect of the local *bar; happened at runtime, so its effect is already over! Which means that now, baz globally redefines bar.
- The final call to quz(); now still sees the original foo, but bar has been redefined globally.
Having said all that, I think local *foo = sub {} is one of those things that should only be used very rarely (one of those "use only if you know what you're doing and why" things).
Aside from the plain wackyness of the above example code, one of the main arguments is that, as always, fiddling with global definitions can cause unintended consequences in other places in the code: if you redefine foo and then call another function, who's to say whether someone down the call tree is depending on the original definition of foo?
The two much better and "more modern" solutions IMO are simply passing around references to (anonymous) subs, or an OO design with classes where methods can be overridden in subclasses; based on what you've written, I suspect the latter might be appropriate in your case, but you'd have to explain a bit more the bigger picture of what you're trying to do.
Update: Yet another reason not to use local *bar; - it localizes everything named bar! Example in readmore tags:
A few more notes on your code:
- "sub stuff() {" - prototypes are ignored on method calls.
- &asub("stuff") - the &foo() style of calling subs disables prototype checking and changes the behavior of @_ (perlsub) - in modern Perl, it has become another one of those "use only if you know what you're doing and why" things.
- eval {...}; if ($@) ... is discouraged, use eval {...; 1} or ... instead, see e.g. Bug in eval in pre-5.14 or the "Background" section of Try::Tiny.
- When posting code examples, the easier it is to run for everyone, the better. In this code, your P appears to be doing the same as printf, so if you'd just use printf, people could just download and run your code instead of installing a new module.
Hope this helps, -- Hauke D
Updated wordings in a few places. | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: how to declare a local *subname=sub{}?
by Marshall (Canon) on Oct 31, 2016 at 04:14 UTC
|
I am very unsure as to your question and the intent of your code? I don't see the need for type glob (*something). What is your objective?
#!/usr/bin/perl
use strict;
use warnings;
# dispatch table...
#
my %table = ('x'=>\&ABC,
'y'=> sub {print "Anon sub for key 'y' in table\n";}
);
sub ABC{print "sub ABC called\n";};
# call routines in the dispatch table...
$table{'x'}->(); # prints: "sub ABC called"
$table{'y'}->(); # prints: "Anon sub for key 'y' in table"
# local can only "mask" an "our" or a global variable, like
# perhaps as in the common idiom:
# my $file = do { local $/; <FILE> };
# which "slurps" an entire file into the $file variable.<br>
# A "my" variable cannot be "localized"
our $xyzzy = 33;
{
local $xyzzy = 55;
print "$xyzzy\n"; #prints 55
}
print "$xyzzy\n"; #prints 33
| [reply] [Watch: Dir/Any] [d/l] |
|
I am very unsure as to your question and the intent of your code?
I share your uncertainty. I think perl-diddler may have invented yet another way to write spaghetti code without using goto. A dispatch table approach such as you exemplify tends to be my knee-jerk approach to the sort of problem that I imagiine gave rise to the OP.
# local can only "mask" an "our" or a global variable ...
...
# A "my" variable cannot be "localized"
I tend to think of this a bit differently. My conception is that a my variable can be completely "localized" or isolated within a scope, whereas an our (or package global) variable cannot. The potential scoped isolation of lexical variables makes it very easy to reason about them, a great advantage.
c:\@Work\Perl>perl -wMstrict -le
"our $xyzzy = 33;
print qq{A: $xyzzy};
{
local $xyzzy = 55;
print qq{B: $xyzzy};
zot();
print qq{C: $xyzzy};
}
print qq{D: $xyzzy};
;;
sub zot { $xyzzy = 99; }
"
A: 33
B: 55
C: 99
D: 33
c:\@Work\Perl>perl -wMstrict -le
"my $xyzzy = 33;
print qq{A: $xyzzy};
{
my $xyzzy = 55;
print qq{B: $xyzzy};
zot();
print qq{C: $xyzzy};
zonk();
print qq{D: $xyzzy};
}
print qq{E: $xyzzy};
;;
sub zot { $xyzzy = 99; }
;;
sub zonk { my $xyzzy = 9999; }
"
A: 33
B: 55
C: 55
D: 55
E: 99
Update: But then there's PadWalker... (sigh)
Give a man a fish: <%-{-{-{-<
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
#!usr/bin/perl
use strict;
use warnings;
our $xyzzy = 33;
print "A: $xyzzy\n";
{
local $xyzzy = 55;
print "B: $xyzzy\n";
zot(); # changes $xyzzy altough no return value
# zot() can modify a global variable
print "C: $xyzzy\n";
}
# $xyzzy is now back at the A: value
print "D: $xyzzy\n";
sub zot {
$xyzzy = 99; #set global "our" var
}
__END__
A: 33
B: 55
C: 99
D: 33
| [reply] [Watch: Dir/Any] [d/l] |
Re: how to declare a local *subname=sub{}?
by Corion (Patriarch) on Oct 31, 2016 at 09:48 UTC
|
As you haven't told us what problems you're trying to address it's hard to give you a good direction to investigate in.
There is an experimental feature named lexical_subs that is supposed to declare lexically scoped subroutine names in the following form:
use feature 'lexical_subs';
sub foo {
my sub secret_foo {
my($arg) = @_;
return "Hello $arg";
};
my( $bar ) = @_;
my $res = secret_foo( $bar );
return "Result is '$res'";
}
print foo('World');
But as far as I know, the feature never left its experimental status and has the same interactions with lexical variables as the traditional approach using lexical variables has. If you want to use local subroutines without polluting the namespace, just use anonymous subroutines:
use feature 'lexical_subs';
sub foo {
my $secret_foo = sub {
my($arg) = @_;
return "Hello $arg";
};
my( $bar ) = @_;
my $res = $secret_foo->( $bar );
return "Result is '$res'";
}
print foo('World');
Using dynamic scope is usually fraught with problems as debugging dynamic scope is difficult. There is a reason why lexical scope was a great thing for Perl 5, and while it is sad that there is no convenient lexical scope for subroutines, working around this with dynamic scope is a bad idea. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
"There is an experimental feature named lexical_subs ... But as far as I know, the feature never left its experimental status ..."
This will probably be non-experimental in the next stable release (i.e. v5.26).
See "perl5252delta: Lexical subroutines are no longer experimental".
Update:
Added "[non-experimental lexical_subs]" to title.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: how to declare a local *subname=sub{}?
by LanX (Saint) on Oct 31, 2016 at 00:08 UTC
|
| [reply] [Watch: Dir/Any] |
Re: how to declare a local *subname=sub{}?
by Anonymous Monk on Oct 30, 2016 at 22:26 UTC
|
$ perl -wle " { local *foo = sub { warn 6}; foo; } foo; "
Unquoted string "foo" may clash with future reserved word at -e line 1
+.
Unquoted string "foo" may clash with future reserved word at -e line 1
+.
Useless use of a constant ("foo") in void context at -e line 1.
Useless use of a constant ("foo") in void context at -e line 1.
$ perl -wle " { local *foo = sub { warn 6}; foo(); } foo(); "
6 at -e line 1.
Undefined subroutine &main::foo called at -e line 1.
What is your question? | [reply] [Watch: Dir/Any] [d/l] |
Re: how to declare a local *subname=sub{}?
by Anonymous Monk on Oct 30, 2016 at 22:16 UTC
|
Is there a version with no P;? | [reply] [Watch: Dir/Any] |