Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Fighting sub foo($;$$)

by Sandy (Curate)
on Apr 14, 2023 at 20:31 UTC ( [id://11151672]=perlquestion: print w/replies, xml ) Need Help??

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

I am currently fighting with some legacy code (which I am embarrassed to say that I wrote myself) which cannot be changed.

In this file, I have a code that is equivalent to:

package Somename; foo(1,2,3,4,5); sub foo($;$$) { my $one = shift; my $two = shift; my $three = shift; my $four = shift; my $five = shift; # long complicated code
This works because I call foo before the subroutine is processed, so there were no flags years ago to fix it.

Today, I need this function foo in another program, so I do this:

use Somename; Somename::foo(1,2,3,4,5);
And now this doesn't work because 'foo' is compiled before I call it.

Is there any chance that I could tell perl to ignore my past foolishness, and just forget that there is '($:$$)'?

Thanks, Sandy

Replies are listed 'Best First'.
Re: Fighting sub foo($;$$)
by haukex (Archbishop) on Apr 14, 2023 at 20:47 UTC
    Is there any chance that I could tell perl to ignore my past foolishness, and just forget that there is '($:$$)'?

    For individual calls, you can bypass prototypes by calling the sub with the old ampersand syntax. See also Prototypes. If however this sub is being called in lots of places, instead of adding a bunch of &s, I would strongly recommend some refactoring of the code instead.

    package Somename; use Data::Dumper; foo(1,2,3,4,5); sub foo($;$$) { print Dumper(\@_) } package main; &Somename::foo(1,2,3,4,5); # works

    I should mention of course that a sub with a prototype ($;$$) and then shifting five arguments is quite a strange piece of code.

Re: Fighting sub foo($;$$)
by ikegami (Patriarch) on Apr 16, 2023 at 00:03 UTC

    The prototype can be ignored by using &.

    &foo( 1, 2, 3, 4, 5 )

    "Import" without prototype:

    sub foo { goto &Somename::foo }
Re: Fighting sub foo($;$$)
by LanX (Saint) on Apr 14, 2023 at 22:17 UTC
    I really doubt this prototype ($;$$) ever served a meaningful purpose...

    But for the general case, you can always write a wrapper which calls the original

    use v5.12.0; use warnings; package Somename; use Data::Dumper; foo(1,2,3,4,5); sub foo($;$$) { my $one = shift; my $two = shift; my $three = shift; my $four = shift; my $five = shift; print Dumper [$four,$five]; } package Othername; # use Somename; sub foo { &Somename::foo } foo(1..5);

    Somename::foo() called too early to check prototype at d:/Perl/pm/foo_ +prototype.pl line 8. $VAR1 = [ 4, 5 ]; $VAR1 = [ 4, 5 ]; Compilation finished at Sat Apr 15 00:12:57

    Explanation for &Somename::foo

    • the & helps ignoring the prototype
    • the missing brackets mean it's called with the current @_
    • the last position means it's return value is returned too.
    NB: you can also define an Somename::import sub which automatically exports the foo you want into the callers namespace, whenever use Somename; is compiled.

    Cheers Rolf
    (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
    Wikisyntax for the Monastery

Re: Fighting sub foo($;$$)
by LanX (Saint) on Apr 14, 2023 at 20:38 UTC
    > Is there any chance that I could tell perl to ignore my past foolishness, and just forget that there is '($:$$)'?

    Why don't you just remove the prototype?

    use v5.12.0; use warnings; package Somename; use Data::Dump qw/pp dd/; foo(1,2,3,4,5); sub foo { my $one = shift; my $two = shift; my $three = shift; my $four = shift; my $five = shift; pp $four,$five; }

    (4, 5)

    FWIW: your old code produced a warning that you apparently ignored in the past°

    Somename::foo() called too early to check prototype at d:/Perl/pm/foo_prototype.pl line 8.

    removing the protoytpe will help you getting rid of this too.

    Cheers Rolf
    (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
    Wikisyntax for the Monastery

    °) or you didn't use warnings

      Why don't you just remove the prototype?

      I'd be careful with that, OP says this is legacy code, and simply removing the prototype could change how the code behaves at call sites that the OP doesn't want to affect. The $ prototype doesn't just mean "accept one argument", it also means "force scalar context on this argument".

      my @ary = ("a","b","c"); sub foo($;$$) { print Dumper(\@_) } sub foo2 { print Dumper(\@_) } foo (@ary, ("x","y"), "z"); # @_ is [3, 'y', 'z' ] foo2(@ary, ("x","y"), "z"); # @_ is ['a', 'b', 'c', 'x', 'y', 'z']
        I was thinking to add a longer explanation about exactly that, but the OP said it's legacy code she wrote herself.

        And I really doubt she tried to impose scalar context on the arguments, especially when it was always called before the prototype was declared.

        Anyway since she never exported it so far, she can easily check the module for all calls.

        Cheers Rolf
        (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
        Wikisyntax for the Monastery

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11151672]
Approved by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (2)
As of 2025-07-18 01:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.