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

(Assuming the PM is sooner alive than dead & I can still read/write here), I noticed some cpan modules have a label (the _: to be specific, mostly in modules by SPROUT, but also perl itself if example is needed) at the end of a sub; it's deparsed into () i.e. empty list. Why? Is this behaviour documented anywhere?

Replies are listed 'Best First'.
Re: Label makes a sub to return empty list -- "secret"? documented?
by dave_the_m (Monsignor) on Sep 11, 2025 at 11:50 UTC
    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.

      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!

      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.

        > 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