http://www.perlmonks.org?node_id=1019982

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

Hello dear Monks again! I have some code:
use strict; my $R; sub mySub { unless ($R) { print "CONDITION WORKS\n"; $R = 'some string'; } } print mySub(); #prints CONDITION WORKS\nsome string print mySub(); #prints some string print mySub(); #again
So, Perl returns last evaluated value. My question is: are there any conditions when Perl would NOT print "some string" in last two lines of code? Thanks!
  • Comment on Perl: last evaluated value as a returned value for a subroutine. See inside
  • Download Code

Replies are listed 'Best First'.
Re: Perl: last evaluated value as a returned value for a subroutine. See inside
by moritz (Cardinal) on Feb 21, 2013 at 17:18 UTC
    My question is: are there any conditions when Perl would NOT print "some string" in last two lines of code?

    I have trouble making sense of this question.

    If you change the code, it might do something differently, depending on how you change it. If you don't change the code, it'll do the same thing each time you execute it.

    If the fact that $R is returned surprises you, it might help to know that

    unless ($A) { $b }

    is actually compiled the same as

    $a or $b

    (and likewise if ($a) { $b } is compiled the same as $a and $b)

    which is why branching constructs as the last statement return the value of the conditional.

Re: Perl: last evaluated value as a returned value for a subroutine. See inside
by choroba (Cardinal) on Feb 21, 2013 at 17:05 UTC
    If you do not want the last value, return something else:
    sub mySub { if ($R) { return; } else { print "CONDITION WORKS\n"; $R = "some string\n"; } }

    Usually, your subroutine should return a value and not print anything, or it should print something, but then you should call it in a void context (or a boolean one, checking for success). Making it both print and return a value to be printed makes it harder for reuse.

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Perl: last evaluated value as a returned value for a subroutine. See inside
by swkronenfeld (Hermit) on Feb 21, 2013 at 17:02 UTC
    Not commenting on the exact behavior of Perl, but I have a coding style suggestion.

    Perl's feature of returning the last evaluated value can be handy when you're writing quick code (or perhaps when you're golfing). But the code you wrote above is not very clear. Hand that to other programmers and I bet many won't know the return value - even plenty of Perl veterans.

    Just because you can do something doesn't mean you should. Write more explicit code. For everyone's sake (including yourself a week/month/year in the future).

      Very strongly agree.

      The problem with a more “lackadaisical” coding style is that it is not immediately apparent what the actual return-value will be ... let alone what it was intended to be.   Even in the case at bar, we see this:   Perl did exactly what it is programmed to do, but the author mistook what that would turn out to be.   (The next person to come along, now frantically trying to find the obscure bug that is torching a production system, is even more “sunk.”)

      If a function returns a value, you should always IMHO return $some_value;.   If the function makes decisions such that it could have more than one “intended result,” put an appropriate return statement at each point.   Not only is there no good reason to let control “dribble down” to the endpoint of the routine, but a subtle and unexpected bug might be introduced if additional code were added at the end of the routine.   Code for clarity.   Hair-follicles are a precious thing.

      won't know the return value - even plenty of Perl veterans.

      doubtful , this knowledge is even more basic than scalar/list context

      perldoc -f return

Re: Perl: last evaluated value as a returned value for a subroutine. See inside
by blue_cowdawg (Monsignor) on Feb 21, 2013 at 17:15 UTC

    I modified your code a bit so you can see what's happening:

    use strict; my $R; my $i=1; sub mySub { printf "\n\n%d. R = \"%s\"\n",$i++,$R; unless ($R) { print "CONDITION WORKS\n"; $R = 'some string'; } } print mySub(); #prints CONDITION WORKS\nsome string print mySub(); #prints some string print mySub(); #again
    This ends up producing this for an output:
    1. R = "" CONDITION WORKS some string 2. R = "some string" some string 3. R = "some string" some string
    On the first iteration $R is undefined and there for in a "false" state. Therefore your print inside the "unless" gets executed and an assignment gets performed on $R. Where it gets trickier is the next iterations. Since you have unless($R) as the last evalutation the value of $R becomes the return value for the sub since you didn't specify one. see sub and search for "return" if you want more on this.


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: Perl: last evaluated value as a returned value for a subroutine. See inside
by LanX (Saint) on Feb 21, 2013 at 17:00 UTC
    your output must be wrong, only the first call should print "some string".

    EDIT: now I get it, the sub returns the evaluation from the unless-condition in the first line.

    ... WTF ...

    You like obfuscation, don't you?

    > are there any conditions when Perl would NOT print "some string" in last two lines of code

    sure if you set $R to anything false ( EDIT:... it will start from new, otherwise it will print the new value.)

    if you wanna avoid that anyone ever unintentionally changes $R, then put the whole closure construct into braces and $R is out of scope for any other code.

    { my $R; sub mySub { unless ($R) { print "CONDITION WORKS\n"; $R = 'some string'; } } }

    Cheers Rolf