Why am I getting "called too early to check prototype" warnings in my Perl code?
Asked Answered
G

6

18

I have a Perl file like this:

use strict;
f1();

sub f3()
{ f2(); }

sub f1()
{}
sub f2()
{}

In short, f1 is called before it is defined. So, Perl throws a warning: "f1 called too early to check prototype". But same is the case with f2, the only diff being that it is called from inside another subroutine. It doesn't throw a warning for f2. Why?

What is the best way to resolve this issue?

  1. declare the subroutine before it is called
  2. call the sub like this: &f1();
Gadroon answered 12/11, 2009 at 5:0 Comment(2)
Please use formatting when posting code samples: indenting lines by 4 spaces will cause them to appear as code in the question, with highlighting and everything.Teasel
You should add the -w switch if you really want this to failNesta
L
19

You can completely avoid this issue by not using prototypes in the first place:

use strict;

f1();

sub f3 { f2() }

sub f1 {}
sub f2 {}

Don't use prototypes unless you know why you are using them:

This is all very powerful, of course, and should be used only in moderation to make the world a better place.

Lamar answered 12/11, 2009 at 5:16 Comment(12)
I don't like the "don't use prototypes" bit. They're quite nice at times, for some things.Teasel
Not using prototypes is one of the reasons people complain about readability and maintainability in Perl.Thunderpeal
@jheddings: You're missing the point: Perl's prototypes are, 99%, not a useful feature. They make the code worse. Don't believe me? Read groups.google.com/group/comp.lang.perl.modules/msg/… . The only useful prototype in perl is (&;@).Volcanology
What is the difference between declaring the function and using & while calling the function? sub f1; &f1();Gadroon
That said, real function signatures are a useful feature. But they don't come with Perl at all, yet. :)Volcanology
Is this really a better solution than just calling &f1()?Nesta
@Chris Lutz: ah, but experienced and knowledgeable users can disregard "don't use X" cautions; they are for the unexperienced and/or unknowledgeable.Donley
@Nathan, no, the solution is not to use the () prototype at all, because it's most likely there for no reason at all.Volcanology
Actually, not using prototypes also solves the problem -- without having to declare the sub before using it.Epilimnion
I agree, don't try to pretend prototypes are function signatures. If you do you (or the person maintaining your code later) will cry. They're there to force context. If you don't understand what that means DON'T USE THEM! The () prototype is relatively innocent but even that causes issues.Therefrom
@hobbs: I have to ask. What does (&;@) indicate? That's a string that's really hard to google.Tennant
@Tennant it's the prototype of a function like map or grep that takes a block as the first argument and any number of arguments in a list afterwards. The information is in perlsub.Volcanology
I
19

Simply remove the () from your subroutine definitions. When you define with (), Perl thinks these are prototypes and you have to define your prototype before you use it.

Try this:

use strict;
f1();

sub f3
{ f2(); }

sub f1
{}
sub f2
{}
Implication answered 6/6, 2015 at 0:26 Comment(0)
T
6

When you define a function in Perl you should not use parentheses. When you do so you get this error. This is wrong:

sub DoSomthing(){
   #do what ever...
}

This is the way to go:

sub DoSomthing{
   #do what ever...
}

no parentheses.

For more detailed explenation see Gabor Szabo's Perl Maven page on Subroutines and functions in Perl. https://perlmaven.com/subroutines-and-functions-in-perl

Tournedos answered 24/8, 2017 at 11:59 Comment(0)
K
3

If you are going to call it with the parenthesis, why are you even using prototypes?

sub f1(){ ... }

f1();

The only time I would use the empty prototype is for a subroutine that I want to work like a constant.

sub PI(){ 3.14159 }

print 'I like ', PI, ", don't you?\n";

I would actually recommend against using Perl 5 prototypes, unless you want your subroutine to behave differently than it would otherwise.

sub rad2deg($){ ... }

say '6.2831 radians is equal to ', rad2deg 6.2831, " degrees, of course.\n";

In this example, you would have to use parenthesis, if it didn't have a prototype. Otherwise it would have gotten an extra argument, and the last string would never get printed.

Ko answered 12/11, 2009 at 16:12 Comment(2)
You've got a spurious "\n" at the end of the say statement thereGalumph
I meant to change it to print so that I didn't have to use feature qw'say'; or use 5.10.1;Ko
I
2

The lack of a warning on the call to f2() from f3() appears to be a bug.

use strict;
use warnings;

f1();

sub f1 {
    my @a = qw(a b c);
    f2(@a);
}

sub f2(\@) { print $_[0] }

This prints "a". If you either predeclare f2() or swap the order of the subroutine definitions, it prints "ARRAY(0x182c054)".

As for resolving the situation, it depends. My preferences (in order) would be:

  1. Remove the prototypes from the subroutine definitions. Perl's prototypes don't do what most people expect them to. They're really only useful for declaring subs that act like builtins. Unless you're trying to extend Perl's syntax, don't use them.
  2. Predeclare the subroutines before using them. This lets Perl know about the prototype before the encountering any calls.
  3. Reorder the code so that the subroutine definitions appear before any calls.
  4. Call the subroutines using the &foo() notation to bypass prototype checking.
Intercommunicate answered 12/11, 2009 at 14:47 Comment(0)
E
0

You can declare it first like C language.

sub test($);

test("xx");

sub test($) {
   # do something
}
Empty answered 28/4, 2021 at 10:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.