Re: use slack;
by chromatic (Archbishop) on Dec 19, 2000 at 08:46 UTC
|
my %actions = (
this => \&this,
that => \&that,
foo => \&foo,
bar => \&bar,
zzz => \&sleepytime,
);
# ooh, tricky
foreach (@user_actions) {
if (defined(my $sub_ref = $actions{$_})) {
$sub_ref->();
}
}
| [reply] [d/l] |
|
Since the original intent appeared to be to run just one subroutine, you can probably even lose the subroutine in chromatics example:
my $in = param('in');
my %actions = (
this => \&this,
that => \&that,
foo => \&foo,
bar => \&bar,
zzz => \&sleepytime,
);
defined(my $sub_ref = $actions{$in}) && $sub_ref->() ;
-mark | [reply] [d/l] |
|
With all due respect to those suggesting the hash, both here and in the chatterbox, saints even. I have 2 problems with the hash:
my %actions = (
this => \&this,
that => \&that,
foo => \&foo,
bar => \&bar,
zzz => \&sleepytime);
1. it resembles the original redundant code that was eliminated:
if($in eq "this"){&this}
if($in eq "that"){&that}
if($in eq "foo"){&foo}
if($in eq "bar"){&bar}
if($in eq "zzz"){&zzz}
2. my feeble attempts to implement it do not even succeed, (very possibly due to my own implementation bugs).
The hash plus every variant of code (supplied in replies) to access it gives me:
with use strict: Can't use string ("\&foo") as a subroutine ref while "strict refs" in use
with no strict "refs"; Undefined subroutine main::\&foo
I really want to collapse the kind of repetition represented in my original code, because i'm adding so many options to some scripts that all the ifs (or the hash) are getting ridiculous. I can replace any number of lines related to testing input with ONE:
foreach(@actions){ if($in eq $_){&$_()}}
I did resort to no strict "refs"; and thanks to alakaboo moved that line inside the foreach loop from the top near use strict;.
$in=param('in');
@actions=qw(this that foo bar zzz);
foreach(@actions){ no strict "refs"; if($in eq $_){&$_()}}
I also like using the array like this because it was already there being used for other purposes! How can this be unsafe in practice? The sub name $_ comes from @actions which is predefined and only happens if input matches it. I've tried feeding it other sub names that exist in the script, but it only executes ones that are defined in the array.
| [reply] [d/l] [select] |
|
Says epoptai:
> Can't use string ("\&foo")
That's because your hash has
that => '\&that',
when it should have
that => \&that,
| [reply] [d/l] [select] |
|
|
(no strict) Re: use slack;
by mwp (Hermit) on Dec 19, 2000 at 11:58 UTC
|
You could cheat and do this:
my $in = $cgi->param('in');
my @actions = qw(this that foo bar zzz);
{
no strict 'refs';
foreach(@actions) {
$_->() if($_ eq $in);
}
}
But I like chromatic's suggestion better.
'kaboo | [reply] [d/l] |
Re (tilly) 1: use slack;
by tilly (Archbishop) on Dec 19, 2000 at 23:38 UTC
|
You do have code for these cases? So in addition to your logic above you have:
sub this {
return "this"; # Whatever
}
sub that {
return "that"; # Being simple here
}
# etc
Combine the two:
my %action = (
this => sub {return "this"},
that => sub {return "that"},
# etc
);
# Then later:
if (exists $action{$in}) {
$action{in}->();
}
In fact if you have a lot of cases you can probably find room to factor:
sub ret_simple_returner {
my $arg = shift;
return ($arg, sub {$arg});
}
my %action = map ret_simple_returner($_), qw(this that);
The point being that every time you eliminate the need to keep two pieces of code in sync you eliminate another possible source of bugs...
| [reply] [d/l] [select] |
Re: use slack;
by Dominus (Parson) on Dec 20, 2000 at 02:45 UTC
|
> Is there a strict way to do something similar?
Sure.
foreach $_(@actions){ if($in eq $_){no strict 'refs'; &$_()}}
There you go.
| [reply] [d/l] |
Re: use slack;
by autark (Friar) on Dec 20, 2000 at 19:18 UTC
|
I hate to turn off strict. Why use strict
if you are only going to turn it off ?
I usually do this:
use strict;
sub foo { print "bar\n" }
my $func = "foo";
my $func_ref = \&{$func};
$func_ref->();
The reason this works is because the construct \&{$func}
is exempt from the rule of strict references. It is as far as I know
not documented in earlier perls, but code support for this construct has
been in for a long time. It is documented in bleadperl IIRC
The construct is often used in AUTLOAD like this:
sub AUTOLOAD {
# get params and function
# ...
my $func_ref = \&{$func};
goto &{$func_ref};
}
Autark.
| [reply] [d/l] [select] |
|
Says autark:
> I hate to turn off strict. Why use strict if you are only going to turn it off ?
Strict is a safety feature. It is there to prevent
you from accidentally doing something dangerous.
Like all safety features, it also prevents some things
that are not really dangerous. For example, sometimes
my kitchen smoke alarm goes off when I am cooking onions.
If what you want is to do something that is not dangerous,
but which the alarm is too stupid to distinguish from
dangerous behavior, it is entirely appropriate to turn
off the alarm. Should I stop cooking onions, out of some superstitious
fear that maybe the alarm knows better than I do?
No, that would be ridiculous.
You asked why have the alarm, if
I am just going to shut it off? That is the wrong question.
I am not going to shut it off all the time;
just when it interferes with my cooking of onions.
The rest of the time, it will be available to perform its
function, which is to warn me
about accidental fires.
The alarm is a means to an end. The goal is to
prevent fires. Keeping the alarm quiet
is not a goal in itself; it is only a way to help prevent
fires. Keeping strict quiet is not a goal in itself, either.
The goal is to avoid the dangerous and difficult bugs that
can result from careless use of symbolic references.
No dangerous problems can occur in this case.
But apparently a lot of people in this thread feel the way you do,
because
we've seen a whole bunch of clumsy, overcoded solutions,
all just to get around turning off the smoke alarm,
when what's really wanted is just to turn off
strict for one line and cook the damn onions already.
| [reply] |
|
I agree that in the AUTOLOAD example it is probably best to just turn off strict rather than to use a weird workaround.
In the example that he started with, I prefer looking up
the correct function in a hash to scanning a list for it.
YMMV. But the two wins I see are that you don't have to
synchronize the name of the function with the name of the
element in the list, and you don't get cow-orkers tempted
to drop the scan and just jump to the function if it exists. (Which takes you from a safe use of symbolic references to a potentially very dangerous one.)
Also the conceptual step of knowing that you can keep functions in a hash is (in my eyes) a worthwhile step forward in sophistication.
| [reply] |
|
if($in){
foreach(@actions){
unless($_ eq /one|/){
if($in eq $_){
no strict "refs"; &$_()}}}}
the (now 400 line) script uses strict. Since i know how to play
by the rules why not also start to break them, since it seems
to pay off so well when done carefully?
UPDATE: I responded too quickly, as autark explained in
the chatterbox, this is the perfect solution. I get to do
what I want without breaking strict with:
if($in){
foreach(@actions){
unless($_ eq /one|/){
if($in eq $_){
do{\&{$_}}->()}}}}
Joy!
| [reply] [d/l] [select] |
|
The strict pragma is lexically scoped, so it
will only affect the innermost block of your program.
Now, there is no rule saying that you have to use strict;,
it's only good advice :-). Though, I'm a bit curious how breaking
these "rules" have paid off ?
Autark.
| [reply] [d/l] [select] |
Re: use slack;
by steveAZ98 (Monk) on Dec 20, 2000 at 20:03 UTC
|
How about changing to a object system. This might releive some of your redundancy?
package myObj;
use strict;
sub new {
return bless {}, $_[0];
}
sub one {
print "One\n";
}
sub two {
print "Two\n";
}
sub three {
print "Three\n";
}
1;
and test code:
#!/usr/bin/perl -w
use strict;
use lib ".";
use myObj;
my $s = myObj->new();
my @cmd = qw( one two three );
foreach (@cmd) { $s->$_(); }
HTH
| [reply] [d/l] [select] |
|
Very interesting steveAZ98. I can see that this technique
will be useful for future projects. Thanks for adding more
light.
I've uploaded the entire script that i was working on when
this question came up here.
It was inspired by the replies to
this question.
Thanks PM!
| [reply] |