Using a scalar as a condition in perl - perl

First timer...so let me know if there is anything that I have not paid attention to whilst posing a question.
The question is how to use a scalar as a condition, as the code below does not work.
my #parameter=('hub');
my %condition;
$condition{'hub'}{'1'}='$degree>=5';
foreach (#parameter) {
if ($condition{$_}{'1'}) {..}
}
I thought that is because the condition is not interpreted correctly, so I also tried the following, which also did not work.
if ("$condition{$parameter}{'1'}") { ..}
Would really appreciate any help. :)

You either want string eval, which evaluates a string as Perl code
if (eval $condition{$_}{'1'}) { ...
or perhaps a more secure approach would be using code references
$condition{'hub'}{'1'} = sub { return $degree>=5 };
if ($condition{$_}{'1'}->()) { ...
In the second example, you are attaching a piece of code to a variable. The $var->() syntax executes the code and evaluates to the return value of the code.

What you are trying to do is to evaluate '$degree>=5' as real code. Rather than trying to evaluate the string as code (which can be done with eval), it's usually safer and often more robust to instead pass a code-reference. You can use a generator subroutine to generate conditional subs on demand, like this:
sub generate_condition {
my ( $test, $bound ) = #_;
return sub { return $test >= $bound; };
}
my %condition;
$condition{'hub'}{'1'} = generate_condition( $degree, 5 );
if( $condition{$parameter}{1}->() ) { ... }
It gets a little more tricky if you want the >= (ie, the relationship itself) to be dynamically created as well. Then you have a couple of choices. One takes you back to stringy eval, with all of its risks (especially if you start letting your user specify the string). The another would be a lookup table within your generate_condition() sub.
generate_condition() returns a subroutine reference that when invoked, will evaluate the condition that was bound in at creation time.
Here's a generalized solution that will accept any of Perl's conditionals and wrap them along with the arguments being tested into a subroutine. The subref can then be invoked to evaluate the conditional:
use strict;
use warnings;
use feature qw/state/;
sub generate_condition {
my ( $test, $relation, $bound ) = #_;
die "Bad relationship\n"
if ! $relation =~ m/^(?:<=?|>=?|==|l[te]|g[te]|cmp)$/;
state $relationships = {
'<' => sub { return $test < $bound },
'<=' => sub { return $test <= $bound },
'==' => sub { return $test == $bound },
'>=' => sub { return $test >= $bound },
'>' => sub { return $test > $bound },
'<=>' => sub { return $test <=> $bound },
'lt' => sub { return $test lt $bound },
'le' => sub { return $test le $bound },
'eq' => sub { return $test eq $bound },
'ge' => sub { return $test ge $bound },
'gt' => sub { return $test gt $bound },
'cmp' => sub { return $test cmp $bound },
};
return $relationships->{$relation};
}
my $true_condition = generate_condition( 10, '>', 5 );
my $false_condition = generate_condition( 'flower', 'eq', 'stamp' );
print '10 is greater than 5: ',
$true_condition->() ? "true\n" : "false\n";
print '"flower" is equal to "stamp": ',
$false_condition->() ? "true\n" : "false\n";
Often when you construct these sorts of things one is interested in leaving one parameter open to bind at call-time rather than at subroutine manufacture-time. Let's say you only want to bind the "$bound" and "$relation" parameters, but leave "$test" open for specification at subroutine call time. You would modify your sub generation like this:
sub generate_condition {
my ( $relation, $bound ) = #_;
die "Bad relationship\n"
if ! $relation =~ m/^(?:<=?|>=?|==|l[te]|g[te]|cmp)$/;
state $relationships = {
'<' => sub { return $_[0] < $bound },
# ......
And then invoke it like this:
my $condition = generate_condition( '<', 5 );
if( $condition->(2) ) {
print "Yes, 2 is less than 5\n";
}
If the goal is to provide late binding of both the lefthand and righthand side in the relational evaluation, this will work:
sub generate_condition {
my $relation = shift;
die "Bad relationship\n"
if ! $relation =~ m/^(?:<=?|>=?|==|l[te]|g[te]|cmp)$/;
state $relationships = {
'<' => sub { return $_[0] < $_[1] },
'<=' => sub { return $_[0] <= $_[1] },
# ...... and so on .....
return $relationship->($relation);
}
my $condition = generate_condition( '<' );
if( $condition->(2,10) ) { print "True.\n"; }
This sort of tool falls into the category of functional programming, and is covered in beautiful detail in Mark Jason Dominus's book Higher Order Perl

What are you expecting? String values are interpreted as true when they are nonempty.
themel#kallisti: ~ $ perl -e 'print "oops\n" if "false" ; '
oops
themel#kallisti: ~ $ perl -e 'print "oops\n" if "" ; '
themel#kallisti: ~ $ perl -e 'print "oops\n" if "\$degree < 5" ;'
oops
If you want to dynamically evaluate code in your conditions, you have to investigate eval. Example:
my #conds=('$foo>42', '$foo>23');
my $foo = 33;
foreach my $cond(#conds) {
print "$cond itself was true\n" if $cond;
print "$cond evaluated to true\n" if eval($cond);
}
prints
$foo>42 itself was true
$foo>23 itself was true
$foo>23 evaluated to true

Related

How best to dynamcially prepare and run user supplied Perl operators

Context:
Perl script initializes itself based on a user-supplied param-file, then acts on a user-supplied source-file to filter out data and do other operations.
The param-file file contains partial perl expression, which are later suppose to be evaled during runtime, for example:
match:!~ col:1 operand:1|2|3
match:=~ col:1 operand:[^123]
match:=! col:1 operand:^DATE
match:=~ col:1 operand:^(?:\s|DATE)
match:-~ col:1 operand:^\s
match:eq col:7 operand:CA
match:eq col:7 operand:DI
match:ne col:1 operand:ACCOUNT
match:ne col:1 operand:POSITIONS
match:== col:8 operand:999
match:!= col:8 operand:999
Hmm, and how about something like this? maybe later, but I need that too
match="ne list" '11, 71, 7'
Briefly, my perl will get the match operator from the user and then needs to filter out (or in) records from the source file based on the other params.
One and simple approach, is eval:
next unless eval "$value $match $operand";
Now, given that I know that the $match will always be the same, the use of eval on EACH input of the source-file, sounds like an overkill.
if ($match eq '!~')
{
next unless $value !~ /$operand/o;
}
elsif ($match eq '=~')
{
next unless $value =~ /$operand/o;
}
elsif ($match eq 'eq')
{
next unless $value eq $operand;
}
...
And I was thinking of having a hash lookup, not sure how to do that. (I wonder on that too), also thinking of closures ...
I'm looking for best and most efficient approach?
Using eval EXPR:
$match =~ /^(?:[=!][~=]|eq|ne)\z/
or die("Unrecognized operator \"$match\"\n");
my $rv;
eval("\$rv = \$value $match \$operand; 1")
or die $#;
Using a dispatch table:
my %ops = (
'=~' => sub { $_[0] =~ $_[1] },
'!~' => sub { $_[0] !~ $_[1] },
'==' => sub { $_[0] == $_[1] },
'!=' => sub { $_[0] != $_[1] },
'eq' => sub { $_[0] eq $_[1] },
'ne' => sub { $_[0] ne $_[1] },
);
my $op = $ops{$match}
or die("Unrecognized operator \"$match\"\n");
my $rv = $op->($value, $operand);
I don't see how closures could be of any use.

idioms for named parameters in object constructors in Perl

In Perl, if I want to use named parameters in an object constructor, my code seems a bit clumsy if I wish to have some validation.
sub new {
my $class = shift;
my $self = {};
my %args = #_;
foreach my $argname (keys %args) {
if ($argname eq 'FOO') { $self->{$argname} = $args{$argname}; }
elsif ($argname eq 'BAR') { $self->{$argname} = $args{$argname}; }
elsif ($argname eq 'BAZ') { $self->{$argname} = $args{$argname}; }
…
else { die "illegal argument $argname\n"; }
}
bless $self;
return $self;
}
Firstly it seems a bit clumsy to have a temporary hash (%args). Secondly the whole if chain seems verbose and tedious.
The latter can be simplified to
if ('-FOO-BAR-BAZ-'=~m/-$argname-/) { $self->{$argname} = $args{$argname} }
else { die "..."; }
but I imagine this can be improved.
If I need to check values, the if … elsif chain is still necessary?
I've searched a little but cannot find a better idiom. Is there one (other than using a Perl OO framework of some sort)
I found myself constantly writing unnecessary code which checked the given parameters. But then I discovered Params::Validate. It is easy to use and if the validation fails it provides very clear and user-friendly error messages. Covering all possible combinations of parameters and their error messages is a tedious task. I prefer this way instead:
use Params::Validate qw/:all/;
sub new {
my $pkg = shift;
validate(
#_, {
foo => { type => SCALAR | ARRAYREF },
bar => { type => SCALAR, optional => 1},
baz => { type => ARRAYREF, default => ['value'] },
quux => { isa => 'CGI' }
}
);
return bless { #_ }, $pkg;
}
And later this code
MyApp::Something->new(
foo => 123,
bbr => 'typo',
quux => CGI->new()
);
becomes:
The following parameter was passed in the call to MyApp::Something::new but was not listed in the validation options: bbr
at test.pl line 14.
MyApp::Something::new(undef, 'foo', 123, 'bbr', 'typo', 'quux', 'CGI=HASH(0x7fd4fa1857e0)') called at test.pl line 27
You can use smart matching
my #validkeys = qw(FOO BAR BAZ);
if ($argname ~~ #validkeys) { # smart matching
$self->{$argname} = $args{$argname};
} else { die ... }
If you don't like the obscurity of the smart match operator you can swing together a regex
my $rx = '^' . join("|", #validkeys) . '$';
if ($argname =~ /$rx/) { ...
for validation you can define a hash of all legal argument and then just test, if the keys are in it or not
for example:
my %legal = ('FOO' => 1, 'BAR' => 1, 'BAZ' => 1);
my %args = #_;
foreach my $argname (keys %args) {
if(exists $legal{$argname}) { $self->{$argname} = $args{$argname}; }
else { die "illegal argument $argname\n"; }
}
about the clumsyness: well that's the to do it in perl
it can use hashes efficiently and the hash literals are readable
Warning! Untested code.
Check for valid keys.
die "invalid args" if grep { ! /^FOO|BAR|BAZ$/ } keys %args;
Store %args.
$self->{$_} = $args{$_} foreach(keys %args);
For completeness I'm adding this answer (to my own question) describing what I'm actually going to do, which is based on elements from several answers.
sub new {
my $package = shift;
# 1. validate argument names
my %args = #_;
my $valid = '^FOO|BAR|BAZ$';
for (keys %args) { die "invalid arg $_\n" unless /$valid/; }
# 2. construct instance from arguments
return bless { #_ };
}
I've accepted Sebastian's answer although I'm not using Params::Validate yet.
Notes:
I'm deploying to a server that has Perl 5.8 (really) but not Params::Validate. I have reasons for not yet pushing for the upgrades to 5.10.x etc.
For my specific circumstance the above strikes a good balance between brevity and readability. I can later add more validation without too much refactoring.
This compensates for one of the advantages of a getter/setter or accessor style methods for setting parameters (compiler catches typos in parameter name as that is the method name) whilst being more concise.
For other people the above will not apply, so I have accepted Sebastian's answer which I feel is the best one in general (YMMV).

Is there a way to replace an if-elsif-else in Perl with something better?

I want to build a bunch of Perl subrotines that all have the same template if elsif elsif else that takes a decision based on a factor variable. Here's an example of subroutine template:
sub get_age{
my $factor=shift;
if ($factor == 1 ){ print "do something" }
elsif ($factor == 2 ){ print "do somthing2" }
elsif ($factor == 3 ){ print "do somthing3" }
elsif ($factor == 4 ){ print "do somthing4" }
else { print "error" }
}
I am wondering if there some design pattern on Perl to replace the if else condition with more elegant solution which easy to maintain in the future specifically if I need to change some of the conditions or delete some of it?
A couple of people have mentioned a dispatch table. There are two things and it's nice to keep them apart sometimes. There's the list of possible things that could happen, and the thing that makes them happen. If you couple the two, you're stuck with your solution. If you keep them separate, you have more flexibility later.
The dispatch table specifies the behavior as data instead of program structure. Here's two different ways to do it. With your example you have integers and something like that might use an array to store things. The hash example is the same idea but looks up the behavior slightly differently.
Also notice that I factor out the print. When you have repeated code like that, try to move the repeated stuff up a level.
use v5.10;
foreach my $factor ( map { int rand 5 } 0 .. 9 ) {
say get_age_array( $factor );
}
my #animals = qw( cat dog bird frog );
foreach my $factor ( map { $animals[ rand #animals ] } 0 .. 9 ) {
say get_age_hash( $factor );
}
sub get_age_array {
my $factor = shift;
state $dispatch = [
sub { 'Nothing!' }, # index 0
sub { "Calling 1" },
sub { 1 + 1 },
sub { "Called 3" },
sub { time },
];
return unless int $factor <= $#$dispatch;
$dispatch->[$factor]->();
}
sub get_age_hash {
my $factor = shift;
state $dispatch = {
'cat' => sub { "Called cat" },
'dog' => sub { "Calling 1" },
'bird' => sub { "Calling 2, with extra" },
};
return unless exists $dispatch->{$factor};
$dispatch->{$factor}->();
}
Update: Make sure you read brian's comment below; basically, it's better to use for instead of given, due to various issues he comments on in his link. I've updated my advice to incorporate his improvements, which he outlines in Use for() instead of given():
If you're on perl 5.10 or newer, given/when is the magic pair you are looking for, but you really should use for/when instead.. Here's an example:
use strict;
use warnings;
use feature qw(switch say);
print 'Enter your grade: ';
chomp( my $grade = <> );
for ($grade) {
when ('A') { say 'Well done!' }
when ('B') { say 'Try harder!' }
when ('C') { say 'You need help!!!' }
default { say 'You are just making it up!' }
}
just making things shorter:
sub get_age1 {
my $age = shift;
$age == 1 ? print "do something" :
$age == 2 ? print "do somthing2" :
$age == 3 ? print "do somthing3" :
$age == 4 ? print "do somthing4" :
print "error"
}
this one makes more sense if the condition can be best expressed as a regex:
sub get_age2 {
for (shift) {
if (/^ 1 $/x) {print "do something"}
elsif (/^ 2 $/x) {print "do somthing2"}
elsif (/^ 3 $/x) {print "do somthing3"}
elsif (/^ 4 $/x) {print "do somthing4"}
else {print "error" }
}
}
here are a few dispatch tables:
the simple one (with a bug):
{
my %age = ( # defined at runtime
1 => sub {print "do something"},
2 => sub {print "do somthing2"},
3 => sub {print "do somthing3"},
4 => sub {print "do somthing4"},
);
# unsafe to call get_age3() before sub definition
sub get_age3 {
($age{$_[0]} or sub {print "error"})->()
}
}
a better one:
{
my %age;
BEGIN {
%age = ( # defined at compile time
1 => sub {print "do something"},
2 => sub {print "do somthing2"},
3 => sub {print "do somthing3"},
4 => sub {print "do somthing4"},
)
}
# safe to call get_age4() before sub definition
sub get_age4 {
($age{$_[0]} or sub {print "error"})->()
}
}
another way to write it:
BEGIN {
my %age = ( # defined at compile time
1 => sub {print "do something"},
2 => sub {print "do somthing2"},
3 => sub {print "do somthing3"},
4 => sub {print "do somthing4"},
);
# safe to call get_age5() before sub definition
sub get_age5 {
($age{$_[0]} or sub {print "error"})->()
}
}
another good way to write it:
{
my $age;
# safe to call get_age6() before sub definition
sub get_age6 {
$age ||= { # defined once when first called
1 => sub {print "do something"},
2 => sub {print "do somthing2"},
3 => sub {print "do somthing3"},
4 => sub {print "do somthing4"},
};
($$age{$_[0]} or sub {print "error"})->()
}
}
Dispatch tables are a perfect fit for this type of design pattern. I've used this idiom many times. Something like this:
sub get_age {
my $facter = shift;
my %lookup_map = (
1 => sub {.....},
2 => sub {.....},
3 => \&some_other_sub,
default => \&some_default_sub,
);
my $code_ref = $lookup_map{$facter} || $lookup_map{default};
my $return_value = $code_ref->();
return $return_value;
}
This works when the argument you are using to determine which case gets executed is going to exist as a key in your hash table. If it is possible that it won't be an exact match then you may need to use regular expressions or some other way to match your input to which bit of code to execute. You can use regexes as hash keys like this:
my %patterns = (
qr{^/this/one}i => sub {....},
qr{^/that/one}is => sub {....},
qr{some-other-match/\d+}i => \&some_other_match,
)
my $code_ref;
for my $regex (keys %patterns) {
if ($facter =~ $regex) {
$code_ref = $patterns{$regex};
last;
}
}
$code_ref ||= \&default_code_ref;
$code_ref->();
See examples/references/dispatch_table.pl
https://code-maven.com/slides/perl/dispatch-table
#!/usr/bin/perl
use strict;
use warnings;
# Use subroutine references in a hash to define what to do for each case
my %dispatch_table = (
'+' => \&add,
'*' => \&multiply,
'3' => \&do_something_3,
'4' => \&do_something_4,
);
foreach my $operation ('+', 'blabla', 'foobar', '*'){
$dispatch_table{$operation}->(
var1 => 5,
var2 => 7,
var3 => 9,
) if ( exists $dispatch_table{$operation} );
}
sub add {
my %args = (#_);
my $var1 = $args{var1};
my $var2 = $args{var2};
my $sum = $var1 + $var2;
print "sum = $sum \n";
return;
}
sub multiply {
my %args = (#_);
my $var1 = $args{var1};
my $var3 = $args{var3};
my $mult = $var1 * $var3;
print "mult = $mult \n";
return;
}
Output:
sum = 12
mult = 45
This may be a place for something like a dispatch table. I haven't done it myself but this page might be a start: http://www.perlmonks.org/?node_id=456530
use Switch;
Read Dispatch Tables in Higher Order Perl.

Eval within if statement

How can I dynamically pass eq or ne inside perl if statement? I tried below but is not working:
my $this="this";
my $that="that";
my $cond='ne';
if($this eval($cond) $that)
{
print "$cond\n";
}
You don't need eval for this. Just use a dispatch table:
sub test {
my %op = (
eq => sub { $_[0] eq $_[1] },
ne => sub { $_[0] ne $_[1] },
);
return $op{ $_[2] }->($_[0], $_[1]);
}
if (test($this, $that, $cond)){
print "$cond\n";
}
if (($cond eq 'eq') xor ($this ne $that)) {
print $cond;
};
But maybe a better and more general approach would be to use perl's functional capabilities and create a hash table of functions:
my %compare = (
eq => sub {shift eq shift},
ne => sub {shift ne shift},
lt => sub {shift lt shift},
like => sub {$_[0] =~ /$_[1]/},
# ....
);
#...
if ($compare{$cond}->($this, $that)) {
print $cond;
};
Whenever you are using eval for runtime code generation, it is best to keep in mind a few details. First, eval is dangerous, so you should eval the smallest, most generic code you can, and check for errors. Second, eval is slow, so you should store the result for later.
{my %cache;
sub compare {
my ($x, $op, $y) = #_;
$cache{$op} ||= eval "sub {\$_[0] $op \$_[1]}" || die "bad op: $op\n";
$cache{$op}->($x, $y)
}}
my $this="this";
my $that="that";
my $cond='ne';
if (compare $this, $cond, $that) {
print "$cond\n";
}
Here the compare function will build a new coderef (with eval) when it sees an operator that it has not had yet. The return value of the eval is checked, and an error is raised if anything when wrong.
This coderef (which expects its values as arguments) is stored in %cache. Then the cached coderef is run with the two values as arguments. This same coderef will be used over and over whenever the same operator is used.

How can I loop through a list of functions in Perl?

I have a list of functions in Perl. Example:
my #funcs = qw (a b c)
Now they all belong to this module Foo::Bar::Stix. I would like to call them iteratively in a loop:
foreach $func (#funcs) {
Foo::Bar::Stix::$func->(%args)
}
where args is a hash of arguments. However I keep getting this error: "Bad name after :: ..." at the line which contains Foo::Bar::Stix::$func->(%args) How do I fix this error?
a b and c are not function objects but strings
Rather than storing the names of the functions in your array, store references to them in a hash so that you can refer to them by name. Here's a simple code example:
#!/usr/bin/perl
use strict;
use warnings;
my %func_refs = (
'a' => \&Foo::Bar::Stix::a,
'b' => \&Foo::Bar::Stix::b,
'c' => \&Foo::Bar::Stix::c
);
foreach my $func_ref ( values %func_refs ) {
print $func_ref->( "woohoo: " ), "\n";
}
{
package Foo::Bar::Stix;
sub a {
my $arg = shift;
return $arg . "a";
}
sub b {
my $arg = shift;
return $arg . "b";
}
sub c {
my $arg = shift;
return $arg . "c";
}
}
If you're stuck with storing the names for some reason, try this:
my $package = "Foo::Bar::Stix";
my #func_names = qw/ a b c /;
foreach my $func_name (#func_names) {
my $str = &{ "$package\::$func_name" }( "woohoo: " );
print $str, "\n";
}
However, this doesn't work under use strict, and because of this I prefer the first solution. Whatever you do, try to avoid using eval. It's unnecessary, and will likely only cause you problems.
Also, most people who work with Perl capitalize it as Perl rather than PERL. Here's a Stackoverflow question on the subject:
How should I capitalize Perl?
Bad answer: use a symbolic reference:
for $func (#funcs) {
&{"Foo::Bar::Stix::$func"}(\%args);
}
Good answer: use a dispatch table:
my %call_func = (
'a' => \&Foo::Bar::Stix::a,
'b' => \&Foo::Bar::Stix::b,
'c' => \&Foo::Bar::Stix::c,
);
...
for $func (#funcs) {
$call_func{$func}->(\%args);
}
Slight change of syntax will give you what you want
Foo::Bar::Stix->$func(%args)
Though this will pass the package name as the first parameter.
You can use can
my #funcs = qw (a b c)
foreach $func (#funcs) {
Foo::Bar::Stix->can($func)->(%args)
}
You could access it through the special %Foo::Bar::Stix:: variable. This gives full access directly to the symbol table. You'll also notice that it works under strict mode.
#! /usr/bin/env perl
use strict;
use warnings;
{
package Foo::Bar::Stix;
sub a{ print "sub a\n" }
sub b{ print "sub b\n" }
sub c{ print "sub c\n" }
}
my #funcs = qw' a b c ';
my %args;
for my $func (#funcs) {
$Foo::Bar::Stix::{$func}->(%args); # <====
}
Another option:
my $symbol_table = $::{'Foo::'}{'Bar::'}{'Stix::'};
my %funcs = (
# we only want the CODE references
'a' => *{ $symbol_table->{'a'} }{'CODE'},
'b' => *{ $symbol_table->{'b'} }{'CODE'},
'c' => *{ $symbol_table->{'c'} }{'CODE'},
);
for my $func (#funcs) {
$funcs{$func}->(%args); # <====
}
If you are going to be doing that for a large number of subroutines, this is how I would load up the %funcs variable.
my %funcs;
BEGIN{
my $symbol_table = $::{'Foo::'}{'Bar::'}{'Stix::'};
for my $name (qw' a b c '){
$funcs{$name} = *{ $symbol_table->{$name} }{'CODE'};
}
}
I wouldn't do this unless you need the subroutines to have both a fully qualified name, and access to it through a hash variable.
If you only need access to the subroutines through a hash variable this is a better way to set it up.
my %funcs = (
'a' => sub{ print "sub a\n" },
'b' => sub{ print "sub b\n" },
'c' => sub{ print "sub c\n" },
);
Note: you could replace "my %funcs" with "our %funcs"