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

When I try:

#!/usr/bin/perl sub aa{2} sub bb{2} my ($a, $b) = (aa, bb); my ($s, $t) = ((2*aa+bb), (2*$a+$b)); say STDERR "$a==", aa; say STDERR "$b==", bb; say STDERR "$s==$t";

I get:

2==2 2==2 4==6

Please tell me what I am doing wrong, as I expected $s and $t to be equal

It can't be perl It must be me Yet what it is I cannot see

Thanks!

Replies are listed 'Best First'.
Re: Constant code
by toolic (Bishop) on Jan 20, 2017 at 15:33 UTC

    Tip #6 from the Basic debugging checklist: Check to see if your code is what you thought it was

    perl -MO=Deparse -p code.pl sub aa { 2; } sub bb { 2; } LINE: while (defined($_ = <ARGV>)) { my($a, $b) = (aa(), bb()); my($s, $t) = (2 * aa(bb()), 2 * $a + $b); # <-------- bb is inpu +t to aa 'STDERR'->say("$a==", aa()); 'STDERR'->say("$b==", bb()); 'STDERR'->say("$s==$t"); } continue { die "-p destination: $!\n" unless print $_; }

    One fix: add parens:

    # v v my ($s, $t) = (((2*aa)+bb), (2*$a+$b));
Re: Constant code (prototype)
by LanX (Saint) on Jan 20, 2017 at 16:46 UTC
    One needs an empty prototype to use subs as bareword constants!

    see perlsub#Constant-Functions

    sub aa(){2} sub bb(){2} my ($a, $b) = (aa, bb); my ($s, $t) = ((2*aa+bb), (2*$a+$b)); say STDERR "$a==", aa; say STDERR "$b==", bb; say STDERR "$s==$t";
    2==2 2==2 6==6

    Otherwise - as others already pointed out - arguments will be swallowed.

    Additionally you'll suffer of a performance penalty because constant subs are not called but inlined.

    Keep in mind that + is likewise a binary and unary operator, i.e. interpretation depends on context and might not DWYM.

    See constant.pm for an easy way to declare most constants.

    And others prefer Readonly.pm to avoid the ambiguities of barewords.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Re: Constant code
by hippo (Archbishop) on Jan 20, 2017 at 15:34 UTC
    (2*aa+bb)

    Is it not the case that your subroutine aa is taking +bb to be its argument rather than adding bb to the result? A deparse should confirm or refute that.

Re: Constant code
by Marshall (Canon) on Jan 20, 2017 at 16:21 UTC
    First, I always put an explicit return statement in a subroutine rather than relying upon "return value of last statement" except in sort{} blocks where no return statement is the norm.

    When you call a sub() in an expression, the paren's are normally required. There are built in functions and ways to make a user defined function work like a built in function with prototypes.

    The simple answer here is to call sub1() and sub2() with no arguments, use sub1(), etc. Don't use a bare word sub name for a normal user defined sub/function.

    #!usr/bin/perl use strict; use warnings; sub sub1{return 2} sub sub2{return 2} my ($a, $b) = (sub1, sub2); my ($s, $t) = ((2*sub1()+sub2()), (2*$a+$b)); say STDERR "$a==", sub1; say STDERR "$b==", sub2; say STDERR "$s==$t"; __END__ 2==2 2==2 6==6

      The simple answer here is to call sub1() and sub2() with no arguments, use sub1(), etc. Don't use a bare word sub name for a normal user defined sub/function.

      And yet, we encourage this all the time in OO paradigms, where we have a member function foo to get the value of 'foo': $obj->foo instead of $obj->foo(), ostensibly because it is a 'value' and the fact that foo is a function is just an implemention detail.

      Fooey, I say: if you end up creating a stack entry, use parens. That's just my curmudgeonly USD 0.02.

        I have seen parentheses-less method calls outside of getting only a (variable) value, namely in cases where no parameters are being passed. (I don't have any examples handy right now.)

        Sorry, that ^ was me.