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

I want a subroutine "verify" that can be called with an optional string and a reference to a scalar variable, like this:
verify $a; verify "hello", $b;
The C++ way would be to overload verify, but I can't do that in Perl:
sub verify(\$) { ... } sub verify($\$) { ... }
Any ideas? I could put the optional string after the reference, but I don't want to. I'm not happy about having to put in an explicit backslash when calling verify, either.

Replies are listed 'Best First'.
Re: Optional parameter before reference
by BrowserUk (Patriarch) on Jul 23, 2004 at 17:44 UTC

    I'd recommend against using prototypes except where neccessary in Perl. They are not equivalent to C/C++ formal parameters.

    But if you must, you can do it this way:

    sub verify ( $;\$) { print "Got:'$_'" for @_; } $s = 'fred'; verify 'this'; Got:'this' verify 'this', $s;; Got:'this' Got:'SCALAR(0x195d844)' verify 'this', 'that';; Type of arg 2 to main::verify must be scalar (not constant item) at (e +val 7) line 1, at EOF

    Note the ';' between the prototype args which make everything after it optional.

    Note also the error generated by the last test above. This is just one of several limitations of Perl prototypes.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon
Re: Optional parameter before reference
by Eimi Metamorphoumai (Deacon) on Jul 23, 2004 at 17:30 UTC
    Easiest way to do it is to check how many parameters you're being passed, or work from the other end.
    sub verify{ my $optional; $optional = (@_ == 2) ? shift : "default value"; my $ref = shift; ... }
    or
    sub verify{ my $ref = pop; my $optional = pop; #becomes undef if only one param }
Re: Optional parameter before reference (!proto)
by tye (Sage) on Jul 23, 2004 at 18:02 UTC
    sub verify { my $ref= \$_[-1]; pop(@_); my( $string )= @_; # ... }

    Lots of variations on that theme are possible. Avoiding subroutine prototypes is usually best with Perl.

    - tye        

      Oh, that's excellent! I'd forgotten that @_'s elements are aliases for the actual scalar parameters. We get the referencing for free, without the caller having to use a backslash.

      This does what I need:

      sub verify { my $ref = \pop; my $string = @_ ? shift : "<default>"; $$ref = $string; # Dummy action for testing } verify $a; verify "hello", $b; print "a=$a b=$b\n"; # Expect a=<default> b=hello

        Interesting. I specifically didn't use \pop because I figured that you'd end up with a reference to a copy. But it makes sense that it is the assignment in "my $x = pop" that does the copying and not the pop. Thanks.

        - tye        

Re: Optional parameter before reference
by LassiLantar (Monk) on Jul 23, 2004 at 17:37 UTC
    You could also check if your first parameter is a reference using the ref function.

    "ref EXPR.... The ref operator returns a true value if EXPR is a reference, false otherwise." (Programming Perl, p.773) It returns the type of thing that the reference refers to (ex. "SCALAR", "ARRAY", "GLOB"...)

    LassiLantar

Re: Optional parameter before reference
by heroin_bob (Sexton) on Jul 23, 2004 at 18:36 UTC
    A way that works for me is to pass in a hashref containing my params. That way the order isn't an issue, they're all in one place, and anything optional can be easilly tested for and used/ignored.
    sub verify { my $params = shift || die("your message"); ... } verify({param1 => $b, param2 => "hello", param3 => "whatever"}); verify({param1 => $b}); verify({param1 => "hello"});

    It can get pretty hairy though passing in nested data.
    ~hb