in reply to Label makes a sub to return empty list -- "secret"? documented?

Its main effect is to add another statement thus ensuring no return value(s), but doing so infinitesimally faster than ending the sub with (). I don't think it's documented anywhere nor officially sanctioned.

Dave.

  • Comment on Re: Label makes a sub to return empty list -- "secret"? documented?

Replies are listed 'Best First'.
Re^2: Label makes a sub to return empty list -- "secret"? documented?
by LanX (Saint) on Sep 11, 2025 at 13:44 UTC
    to make this clearer for beginners:
    • in Perl a sub returns the result of the last statement¹
    • to avoid unwanted results a last statement can be an "empty" return (recommended by PBP)
    • an empty list () as last statement is faster because two opcodes for return are avoided
    • a LABEL: without following code is even faster because a new statement is enforced without any opcode
    • "_" is a legal identifier but has no magic meaning as label, IOW it's a convention
    I wouldn't call the effects undocumented, just an idiomatic approach (and micro optimization)

    FWIW using a label can have unwanted global side-effects, because a nested sub could have a goto _;

    some experiments:

    $ perl -MO=Concise,ret,empty,label -e'sub ret {return}; sub empty {()} +; sub label {LABLE:};' main::ret: 4 <1> leavesub[1 ref] K/REFC,1 ->(end) - <@> lineseq KP ->4 1 <;> nextstate(main 2 -e:1) v ->2 3 <@> return K ->4 2 <0> pushmark s ->3 main::empty: 7 <1> leavesub[1 ref] K/REFC,1 ->(end) - <@> lineseq KP ->7 5 <;> nextstate(main 4 -e:1) v ->6 6 <0> stub P ->7 main::label: 9 <1> leavesub[1 ref] K/REFC,1 ->(end) 8 <;> nextstate(LABLE: main 6 -e:1) P ->9 -e syntax OK

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

    UPDATE

    ¹) jdporter pointed out: you say "last statement", but you mean "last expression evaluated". Not the same thing!

    well yes not every statement is an expression leading to a value, and it's the last in the current code flow which counts (think if/else), not in the sub.

    That's what the docs say:

    If no return is found and if the last statement is an expression, its value is returned. If the last statement is a loop control structure like a foreach or a while, the returned value is unspecified. The empty sub returns the empty list

      I would have expected the empty return to have been optimized away during compilation two decades ago at least.

      Jenda
      1984 was supposed to be a warning,
      not a manual!

        well B::Deparse would fail then ...

        There is also benefit in consistent behavior.

        I'd rather prefer a second version of the sub construct (something like def ) which implements this, instead of relying on such syntax tricks.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

Re^2: Label makes a sub to return empty list -- "secret"? documented?
by Anonymous Monk on Sep 12, 2025 at 20:09 UTC

    Thanks, everyone. FWIW (I usually distrust multi-millions-per-sec benchmarks):

    cmpthese 5e7, { 1 => sub { my $x = 1 + 1; return }, 2 => sub { my $x = 1 + 1; () }, 3 => sub { my $x = 1 + 1; _: }, }; 1 27367269/s -- -13% -22% 2 31367629/s 15% -- -11% 3 35161744/s 28% 12% --

    "Perl subs are expensive"? The cheapest adjustment is just above. Otoh, now I have a justification (not that I need any or anyone cares) not to follow PBP's "Place the label on the line preceding the loop keyword" -- just in case, easier and safer while debugging and commenting-out this or that, to keep label and code on the same line.

      Sometimes, I prefer to invert the numbers to get the time saved to put things into perspective.

      27367269 calls/s = 37 ns/call 31367629 calls/s = 32 ns/call 35161744 calls/s = 28 ns/call

      So _: is 9 ns faster than return (assuming the numbers are meaningful).

      After 100 million calls, you still wouldn't have saved a second by switching from return to _:.

      Update: I had moved a decimal point in the wrong direction. Fixed.

        27367269 calls/s = 0.365 ns/call

        I think your numbers are a couple of orders of magnitude out. By my maths 1 / 27367269 = 0.0000000365, so that's 36.5ns per call.

        Even so, your point is valid. It is only in extreme cases where any of this is really worth worrying about.


        🦛

      > Otoh, now I have a justification (not that I need any or anyone cares) not to follow PBP's "Place the label on the line preceding the loop keyword" --

      That's a weird logical construct

      There was no indication or benchmark in this thread so far that placing a label at a previous line comes with a notable performance overhead.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

        It's not performance this time. Intuitively, labels belong to the same "subordinate" "category" as e.g. semicolons, both not far from comments and white-space. Extra semicolon at the end of a block doesn't change what this block evaluates to. Lone label, I now know, does, which is dangerous. Neglected to have been (temporarily?) commented-out along with its loop (if placed per PBP at the next line) and maybe some further statements. Of course, it's the same weird nonsense, please ignore.