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

Right now I have essentially this:
sub get_name { my $name = dblookup() || undef; $name; } my $name = get_name(); if ( $name ) { print "\n My name is $name"; } else { print "\n I have no name"; }
I feel like there exists some special perl way that would do something like:
sub get_name { my $name = dblookup() || undef; $name; } if ( get_name() ) { print "\n My name is $_"; } else { print "\n I have no name"; }
But I haven't found one in any of the docs. It probably doesn't exist, but I'm really wondering if it does now. It seems so... perlish.

Replies are listed 'Best First'.
Re: Can i make this more efficient with a special variable?
by ikegami (Patriarch) on Jan 10, 2006 at 21:07 UTC
    There's nothing inefficient in there. You could remove the useless || undef, since the value is already false and you check for true/false not defined/undefined.
    sub get_name { my $name = dblookup() || undef; $name; }
    becomes
    sub get_name { my $name = dblookup(); $name; }
    becomes
    sub get_name { dblookup(); }
    becomes
    *get_name = \&dblookup;
    As for the if, you could do
    if ( my $name = get_name() )
      thanks for your suggestions. i'm going to use them.
Re: Can i make this more efficient with a special variable?
by kirbyk (Friar) on Jan 10, 2006 at 21:09 UTC
    I don't know of any special variable that means 'the value from the last if test expression'. You could do:
    if ( $name = get_name() ) { print "\n My name is $name"; }
    And that wouldn't even be hard for others to read and maintain.

    Also, is there a reason you don't use return in sub get_name? I know you don't have to, but it makes it _much_ easier to detect bugs if you insert new lines at the end of the sub (or, someone else who isn't paying enough attention to your code does.) I'd generally consider always saying 'return' when you want to return a value as one of those habits of highly successful perl programmers.

    -- Kirby, WhitePages.com

      ok. i thought the value from the last if expression would be some sort of special variable in the local block. nice to know there's not.

      the solution you suggested looks to work well for my needs.

      as for the formatting of the function... it's simple--

      typically more people here yell at me (and others) for writing " return $var " than " $var "
        ok. i thought the value from the last if expression would be some sort of special variable in the local block. nice to know there's not.

        Well, not that nice, but I've never really felt the lack of such a beast. OTOH you can do an aliasing in a syntactically sweet enough way as hinted at the very end of my other reply.

        typically more people here yell at me (and others) for writing " return $var " than " $var "

        Right! it's a very common and unambiguous perlism. I'm all with you, as you can see in my comment to his reply.

      Also, is there a reason you don't use return in sub get_name? I know you don't have to, but it makes it _much_ easier to detect bugs if you insert new lines at the end of the sub (or, someone else who isn't paying enough attention to your code does.) I'd generally consider always saying 'return' when you want to return a value as one of those habits of highly successful perl programmers.

      This is by large a matter of personal taste/preference. I'm not striving for "extreme" conciseness, as that would be "golf" and doesn't make for clarity, but the "Right(TM)" degree of conciseness, which includes avoiding redundant or unnecessary syntax, does make for it. In particular the last line of a sub is already visually distinct enough and I generally consider never saying return unless I want to explicitly return prematurely.

      It's not exactly the same thing but the advice of always returning reminds me of the cargo-culted habit of always including an unnecessary

      exit 0;

      line at the end of one's scripts.

Re: Can i make this more efficient with a special variable?
by blazar (Canon) on Jan 11, 2006 at 09:13 UTC

    Since you ask about efficiency... I don't see anything particularly inefficient in your code. And it's worth stressing once more that "premature optimization is the root of all evil". If you were that concerned about "efficiency", and had good reasons to, then probably you shoudn't have chosen Perl as the implementation langauge; or at least you should write (say) in C the critical parts of your code.

    In particular, in this case you call dblookup() which suggests a database lookup: chances are then that a hugely bigger proportion of time is spent for the latter than for anything else you're doing in perl. One more reson for which any other "efficiency" improvement would be at best marginally noticeable, if at all!

    Said this,

    sub get_name { my $name = dblookup() || undef; $name; }

    is just the same as

    sub get_name { dblookup() || undef }

    (BTW: are you sure you need || undef?)

    But in that case you can save one unnecessary assignement. So you actually get a few less opcodes:

    $ perl -MO=Concise,get_name1,get_name2 sub get_name1 { my $name = dblookup() || undef; $name; } sub get_name2 { dblookup() || undef } main::get_name1: b <1> leavesub[1 ref] K/REFC,1 ->(end) - <@> lineseq KP ->b 1 <;> nextstate(main 1 -:3) v ->2 8 <2> sassign vKS/2 ->9 - <1> null sK/1 ->7 5 <|> or(other->6) sK/1 ->7 4 <1> entersub[t2] sKS/TARG,1 ->5 - <1> ex-list sK ->4 2 <0> pushmark s ->3 - <1> ex-rv2cv sK/1 ->- 3 <$> gv(*dblookup) s/EARLYCV ->4 6 <0> undef s ->7 7 <0> padsv[$name:1,2] sRM*/LVINTRO ->8 9 <;> nextstate(main 2 -:4) v ->a a <0> padsv[$name:1,2] ->b main::get_name2: i <1> leavesub[1 ref] K/REFC,1 ->(end) - <@> lineseq KP ->i c <;> nextstate(main 3 -:7) v ->d - <1> null K/1 ->- g <|> or(other->h) K/1 ->i f <1> entersub[t1] sKS/TARG,1 ->g - <1> ex-list sK ->f d <0> pushmark s ->e - <1> ex-rv2cv sK/1 ->- e <$> gv(*dblookup) s/EARLYCV ->f h <0> undef s ->i - syntax OK

    However I want to stress that althoug I recommend doing so for clarity and conciseness, that's hardly relevant "efficiency"-wise. Otoh, one field in which perl is known not to be particularly fast is parameter passing into subs.

    Now, since you sub doesn't actually take any parameter, you can inform the compiler about this circumstance, and it will take care of optimizing it:

    $ perl -MO=Concise,get_name sub get_name () { dblookup() || undef } main::get_name: 7 <1> leavesub[1 ref] K/REFC,1 ->(end) - <@> lineseq KP ->7 1 <;> nextstate(main 1 -:1) v ->2 - <1> null K/1 ->- 5 <|> or(other->6) K/1 ->7 4 <1> entersub[t1] sKS/TARG,1 ->5 - <1> ex-list sK ->4 2 <0> pushmark s ->3 - <1> ex-rv2cv sK/1 ->- 3 <$> gv(*dblookup) s/EARLYCV ->4 6 <0> undef s ->7 - syntax OK

    Again, generally it's recommendable to factor code into subs, but in this case I don't see a big advantage over inlining the call to dblookup(). Then you can use a for loop for the sole purpose of aliasing $_: I often do, although others disagree on such a practice - you're warned! But this won't "improve efficiency" - yet, again, this hardly matters:

    print $_ ? "\n My name is $_" : "\n I have no name" for dblookup() || +undef;