Re: Action at a great distance
by perrin (Chancellor) on Mar 17, 2004 at 19:43 UTC
|
| [reply] |
|
|
my @cb = (\&callback);
$_->() foreach (@cb);
sub callback {
open(my $fh, "/tmp/somefile") or die;
while(<$fh>) {
print "orange!\n" if /red/;
}
}
The observed behavior was an 'undefined subroutine' error -- and yet, if you cut & paste the above code, it will run fine. (So the above is buggy, but simply running it will not reveal the error.)
Spoilers ahead...
| [reply] [d/l] [select] |
|
|
In this case, I'd say it's bad style to use $_ instead of a named variable for that loop anyway. You could localize $_, but I'd consider that an uglier solution.
| [reply] |
|
|
This is exactly why I try not to use $_ unless in map or grep (but it's not like I have a choice there anyway). This foreach shortcut is ripe with problems just like this. I have always felt that it is much better to take the few seconds of time to type what you mean explicity rather than have to spend alot more time hunting around for an insidious bug like this. That is the right kind of laziness IMO.
I hate to say it, but its idioms like this that give perl such a bad rap. Sure you can bang out a script in 30 seconds that does the work of 6 Java programmers, but at what cost? There is nothing worse than having to maintain a 12-headed monster that was born as that 30 second script. Do future programmers a favor, hell do the perl community as a whole a favor, and take the time to type the few extra characters (Note to OP: this is not directed at you specifically but at the perl community-at-large).
Now go ahead do what you will, I care not for the XP ;-P
-stvn
| [reply] [d/l] [select] |
|
|
;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}}
split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
| [reply] |
|
|
| [reply] [d/l] [select] |
Re: Action at a great distance
by stvn (Monsignor) on Mar 17, 2004 at 22:04 UTC
|
Sorry, but I don't see why (on its own) this is a bad idea. If @callbacks is under your complete control and you know that all your callback subs behave according to some set of rules then I see little wrong with it. If however @callbacks is not under your control then you have a different issue. At that point I would recommend a series of checks:
foreach my $callback (@callbacks) {
(ref($callback) eq "CODE") || die "$callback is not a code ref";
my @temp_args = @{[@args]};
$callback->(@temp_args);
if (verify(@temp_args)) {
@args = @temp_args;
}
else {
die "callback did something funky to args";
}
}
I'm sorry, but given the amount of information you have supplied here, I don't really see what you are trying to get at. Callbacks are a common enough idiom, but when used loosly they can be dangerous, but if you really wanna go there then you could say that plain old assignment (=) is dangerous.
Please provide a bit more information on the code, and how things like @callbacks and @args get populated, along with maybe a bit more context as to where this all gets executed.
-stvn | [reply] [d/l] [select] |
|
|
You're trying too hard, IMO.
my @copy_args;
foreach( @callback ) {
local $_ = $_;
$_->( @copy_args = @args );
}
Makeshifts last the longest.
| [reply] [d/l] |
|
|
Maybe, but TIMTOWTDI. Your code solves the problem for sure, my code assumes that everyone is out to get me, and that nothing is safe. But if you read my post, I suggested that code if the sub refs in @callbacks we "untrusted", not a just a solution to the problem. But again, TIMTOWTDI, and my way is certainly the more paranoid way.
- stvn
| [reply] [d/l] |
|
|
|
|
|
|
|
Btw, this is superflous:
my @temp_args = @{[@args]};
You are making a copy of a copy of the original. Semantically it is the same as
my @temp_args = @args;
Makeshifts last the longest.
| [reply] [d/l] [select] |
|
|
if (verify(@temp_args)) {
@args = @temp_args;
}
else {
die "callback did something funky to args";
}
Then actually doing a proper deep-copy of @args would only make sense if you planned to catch the exception being thrown in the else block. Basically, my intention was to build a sandbox for the callbacks to run in with commit and rollback functionality. A real implementation would require much more knowledge of the data in @args and the functionality of the app as a whole.
-stvn | [reply] [d/l] [select] |
Re: Action at a great distance
by NetWallah (Canon) on Mar 17, 2004 at 19:28 UTC
|
This is a bad idea because ..
Offense, like beauty, is in the eye of the beholder, and a fantasy.
By guaranteeing freedom of expression, the First Amendment also guarntees offense.
| [reply] [d/l] |
|
|
use strict;
use Test::More tests => 1;
my @cb =
(
sub { $_[0] = reverse $_[0] },
sub { $_[1] = reverse $_[1] },
);
my @args = qw( one two );
for my $cb (@cb)
{
$cb->((@args));
}
is_deeply( \@args, [qw( one two )] );
Besides that, any argument passing in Perl has that drawback. | [reply] [d/l] |
|
|
Dude... those parentheses don't cause the array to be copied. If you want do an in-line copy like that, I recommend:
foreach (@callbacks) {
$_->( @{[ @args ]} );
}
------------
:Wq
Not an editor command: Wq
| [reply] [d/l] [select] |
|
|
$->( @{ \@args } );
| [reply] [d/l] |
|
|
|
|
## I.e. just as "dangerous"
foo( @args );
blah( @args );
zorch( @args );
| [reply] [d/l] |
Re: Action at a great distance
by jonadab (Parson) on Mar 17, 2004 at 19:45 UTC
|
How are your two arrays, @callbacks and @args,
populated?
;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}}
split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
| [reply] |
Re: Action at a great distance (not a revelation)
by Aristotle (Chancellor) on Mar 20, 2004 at 08:01 UTC
|
How is any of this any surprise? It's just Yet Another Imprudent Use Of $_. We have seen so many cases like these. A common trap seems to be calling a function with a while(<>){} from inside a map or such. There are examples up the wazoo about this kind of trap.
Always localize $_ before you clobber it!!
It's that simple. Don't act all surprised when you get bitten in the rear if you don't. The only time you can skip this step is foreach, map, and grep, because they alias, rather than assign, to $_. Other than those, localize without even thinking. Make it a habit. Make it a habit. Really, make it a habit.
Makeshifts last the longest.
| [reply] [d/l] |
Re: Action at a great distance
by waswas-fng (Curate) on Mar 17, 2004 at 21:47 UTC
|
I guess I am missing why this is a "Really Bad Idea". I guess I could see:
foreach (@callbacks) {
$_->(@args);
$_->(@otherargs);
}
Misbehaving if $_ was modified, but thats not an issue on the OP's code. | [reply] [d/l] |