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