Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Shortening "$bar{foo} if exists $bar{foo}"?

by BUU (Prior)
on Oct 03, 2003 at 22:05 UTC ( [id://296408]=perlquestion: print w/replies, xml ) Need Help??

BUU has asked for the wisdom of the Perl Monks concerning the following question:

Perhaps it's just me and my personal coding style, but I find I tend to use hashes for a large variety of things involving user input and certain actions based upon that input, much likes a switch statement. So I often have things like
$bar{foo}->() if( exists $bar{foo} );
And this always struck me as really fairly ugly, not to mention long. So does anyone have anyway to shorten that? I suppose you could do something like:
$qux = $bar{foo}; $qux->() if $qux;
But that doesn't really gain anything.

This is a test

Replies are listed 'Best First'.
Re: Shortening "$bar{foo} if exists $bar{foo}"?
by Zaxo (Archbishop) on Oct 03, 2003 at 22:49 UTC

    The deref op '->' is unnecessary there, and there is an alternative of nearly the same length with the and op, exists $bar{'foo'} and $bar{'foo'}();

    After Compline,
    Zaxo

      Actually, it wasn't all *that* long ago when the -> wasn't optional in that construct (I believe 5.006 is when that happened and perldelta agrees with me).

      It is getting close to long enough ago that I'd forget this fact -- except that I tend to answer a lot of questions from people about Perl and many of those people have surprisingly old versions of Perl. (:

                      - tye
Re: Shortening "$bar{foo} if exists $bar{foo}"?
by diotalevi (Canon) on Oct 03, 2003 at 22:28 UTC
    ($bar{foo} || sub{})->()

    I wouldn't actually write that though. I'd write it the way you originally stated: expr->() if expr.

Re: Shortening "$bar{foo} if exists $bar{foo}"?
by Aristotle (Chancellor) on Oct 03, 2003 at 22:42 UTC
    I've been bothered by code duplication when using exists many a time. Unfortunately, I've never ever found a satisfactory solution (and believe me, it's not for lack of trying).

    Makeshifts last the longest.

      How about this Perl6-ish way:

      given %foo{bar} { .() if exists }
      It's still about as much typing, though.

      kelan


      Perl6 Grammar Student

Re: Shortening "$bar{foo} if exists $bar{foo}"?
by sgifford (Prior) on Oct 04, 2003 at 04:48 UTC
    You can write a short, one-time sub to do it:
    #!/usr/bin/perl -w use strict; use vars qw(%bar); $bar{foo} = sub { print "hello\n"}; callif($bar{foo}); callif($bar{quux}); sub callif { my $var = shift; $var->(@_) if($var); }
Re: Shortening "$bar{foo} if exists $bar{foo}"?
by Roger (Parson) on Oct 04, 2003 at 08:07 UTC
    You don't need the exists keyword either, the following symetric code should work just fine -

    # define your hash entry $foo{bar} = sub { print "Hello Perl!\n" }; # note the use of && operator, which will short-circuit # if $foo{bar} is undef. $foo{bar} && $foo{bar}();

Re: Shortening "$bar{foo} if exists $bar{foo}"?
by bart (Canon) on Oct 04, 2003 at 09:52 UTC
    You can use for or foreach for aliasing variables or array/hash elements. Like this:
    for($bar{foo}) { $_->() if $_; }
    That's handy for very long expressions, and, when you assign something to $_, the original value of $bar{foo} will be changed too (that's what "aliasing" means), but I think you won't think it much of a gain in this simple case, either, as it still looks like your last example.
Re: Shortening "$bar{foo} if exists $bar{foo}"?
by tilly (Archbishop) on Oct 05, 2003 at 18:43 UTC
    I'm surprised that I didn't find a module like this on CPAN...
    package Tie::HashDefaultValue; require Tie::Hash; @ISA = 'Tie::ExtraHash'; use strict; sub TIEHASH { my ($class, $default) = @_; return bless [{}, $default], $class; } sub FETCH { my ($tied, $key) = @_; if (exists $tied->[0]{$key}) { return $tied->[0]{$key}; } else { return $tied->[1]; } } 1;
    And now you can just:
    tie my %bar, 'Tie::HashDefaultValue', sub {}; # time passes $bar{foo}->();
    If anyone wants to add documentation, tests, etc to the above module and load it into CPAN as yours, be my guest.

    PS While writing the above I found a documentation mistake in Tie::Hash. Bug report submitted...

    UPDATE: Reading the Tie::Hash source more carefully, I saw that the default TIEHASH function does what mine does, and so that is not needed. If you wish to have people complain about Perl punctuation, here is an amusing implementation of FETCH:

    sub FETCH { exists $_[0][0]{$_[1]} ? $_[0][0]{$_[1]} : $_[0][1] }
Re: Shortening "$bar{foo} if exists $bar{foo}"?
by Aristotle (Chancellor) on Oct 04, 2003 at 17:23 UTC
    You know, it just occured to me that in this specific case you can just
    eval { use strict 'refs'; $bar{foo}->() };

    Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://296408]
Approved by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (5)
As of 2024-04-25 17:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found