in reply to interpolating operators within strings

G'day abualiga,

As ++NetWallah points out, eval can be unsafe.

If your eval code started off like this:

$ perl -Mstrict -Mwarnings -E 'say eval for map { "12 $_ 3" } qw{+ - * + / % **}' 15 9 36 4 0 1728

Using a despatch table like this is a safer option.

$ perl -Mstrict -Mwarnings -E ' my %op_hash = ( q{+} => sub { $_[0] + $_[1] }, q{-} => sub { $_[0] - $_[1] }, q{*} => sub { $_[0] * $_[1] }, q{/} => sub { $_[0] / $_[1] }, q{%} => sub { $_[0] % $_[1] }, q{**} => sub { $_[0] ** $_[1] }, ); say for map { $op_hash{$_}->(12, 3) } qw{+ - * / % **}; ' 15 9 36 4 0 1728

And you can add your own sanity checks:

$ perl -Mstrict -Mwarnings -E ' my %op_hash = ( q{+} => sub { $_[0] + $_[1] }, q{-} => sub { $_[0] - $_[1] }, q{*} => sub { $_[0] * $_[1] }, q{/} => sub { die "Divide by zero!" if $_[1] == 0; $_[0] / +$_[1] }, q{%} => sub { $_[0] % $_[1] }, q{**} => sub { $_[0] ** $_[1] }, ); say for map { $op_hash{$_}->(12, 0) } qw{+ - * / % **}; ' Divide by zero! at -e line 6.

I don't know what context you're intending to use this in: the overload pragma may be of some use.

Update: s/unsafe:/unsafe./ and added "If your eval code started off like this: "

-- Ken

Replies are listed 'Best First'.
Re^2: interpolating operators within strings
by educated_foo (Vicar) on Apr 14, 2013 at 03:51 UTC
    How is anything in your example unsafe? I am reminded of MJD's righteous takedown of a similar superstitious warning (see slide 31).
      Thanks educated_foo, I'd not seen that presentation before, and it's well worth a read :)
Re^2: interpolating operators within strings
by abualiga (Scribe) on Apr 14, 2013 at 03:29 UTC

    Your insight is much appreciated! I was trying to do addition and subtraction of two lists of paired numbers and wanted to avoid separate loops.

      Well, in that case, you might be better off with the pairwise function of List::MoreUtils:

      $ perl -Mstrict -Mwarnings -E ' use List::MoreUtils qw{pairwise}; my @x = 0 .. 3; my @y = map { 10 + $_ } @x; say for pairwise { "$a + $b = " . ($a + $b) . "; $b - $a = " . ($b - $a) } @x, @y; ' 0 + 10 = 10; 10 - 0 = 10 1 + 11 = 12; 11 - 1 = 10 2 + 12 = 14; 12 - 2 = 10 3 + 13 = 16; 13 - 3 = 10

      Note how $a holds @x elements and $b holds @y elements. These ($a & $b) are the same special variables used by sort, so don't declare them; they're described in perlvar - SPECIAL VARIABLES - General Variables. You can use them in either order: cf. $a + $b and $b - $a.

      -- Ken

Re^2: interpolating operators within strings
by TJPride (Pilgrim) on Apr 14, 2013 at 13:34 UTC
    If you first use a regex to remove anything that isn't an operator, a number format, or a space, then it's perfectly safe to eval from there.