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

When running a script using strict, I am getting the warning:

main::usage() called too early to check prototype at X:\bin\backup.pl +line 18. main::usage() called too early to check prototype at X:\bin\backup.pl +line 26.

Does perl require function prototypes similiar to C under certain circumstances?

Code that produced the error (for reference):

#!/usr/bin/perl -w # # backup - perform a daily or weekly backup of a preset list of files. # by Micah Valine (mvaline@buffnet.net) # use strict; ### program settings ### my $daily_backup_dir = "X:\\backup\\daily\\"; my $weekly_backup_dir = "X:\backup\\weekly\\"; my $filelist = "X:\\.backup"; my $daily_flag = "d"; my $weekly_flag = "w"; my $target; ### process arguments ### usage() if (!@ARGV); if ($ARGV[0] eq "-d") { $target = $daily_flag; } elsif ($ARGV[0] eq "-w") { $target = $weekly_flag; } else { usage(); } ### usage: print usage information and die ### sub usage() { print STDERR << "END_USAGE"; usage: backup [-dw] -d performs a daily backup -w performs a weekly backup END_USAGE exit 1; }

Replies are listed 'Best First'.
Re: Function Prototypes
by tadman (Prior) on Jul 03, 2001 at 16:47 UTC
    If you're going to define a Perl function prototype, which is optional, by the way, then you have to define it before it gets used the first time. Otherwise, you get the message which you got. Not that getting the message is a bad thing, since you're using both '-w' and 'use strict', so you're on the right track.

    Try putting your function definition of usage before it is used. It's not a bad practice to get used to.

    Typically you can skip the prototype declaration for a function. It is a relatively recent introduction and prototypes are only required in a very small number of circumstances. In some cases they can make your life easier, but generally they are extraneous.

    As a note, Perl function prototypes are a little different from the usual C ones:
    sub func($@) { my($x,@y) = @_; }
    You declare the types of variables in your specification, not what they are called. The break-out phase is separate, not unlike way old-school K&R C.

    As a general procedure, I usually structure programs like:
    #!/usr/bin/perl -w use strict; use VariousModules; use More::Modules; # -- Globals ------- my $style = "Round"; # -- Functions ------ sub something { my ($new_style) = @_; } # -- Main Code ------ my $thing = something($style); something_else($thing); # -- End ------------
      Prototypes are there only in 5.6 and higher, plus I wouldn't use them as their behavior is very ... well, un-behaved. Perl6 is s'posed to nail down the behavior of prototyping further.
Re: Function Prototypes
by andreychek (Parson) on Jul 03, 2001 at 16:49 UTC
    When you define your subroutine, it does not require parenthesis. Like so:
    # Sub definition sub usage { blah... } # Calling the sub usage();
    You only want to use parenthesis if you want to restrict the parameters which may be sent to it. In this instance, that may be the case, but it seems as if you may have done it by accident ;-) If you do choose to use these parenthesis in the sub definition, it's called a prototype.
    -Eric

    Updated: As currently written, your program doesn't run because you call the subroutine using:
    usage();
    When you use a prototype to forbid parameters, you cannot use parenthesis in the subroutine call. You can just use:
    usage;
    Now, for someone better with prototypes then myself -- I know this works, because I double checked with the Camel Book before posting. But I don't know _why_ this is the case. On page 226 of Camel 3, it says that with the prototype sub mytime(), one should call it using mytime.

    However, going back a few pages to page 222, it talks about how to call subroutines, and what the differences are. It claims that saying foo(); passes a null list to the sub. It then says that using foo; is the same as foo();. Now, that can't be 100% true, if the one won't work with prototypes, but the other does. Does someone know how this is really working?

      When I removed the parentheses from my subroutine (sorry for using function before) definition, the error ceased to appear.

      Updated: Given what Zaxo said below, why does the error disappear when I remove the perentheses from the subroutine definition? Since I am in fact no longer "prototyping" the subroutine, does it just relax and assume that I know what I'm doing when I call it before it has been defined? It seems that perl -w and use strict still ought to catch the fact that I'm calling the it before it's been defined.

        Page 226 of Camel 3 says "...prototypes are taken into consideration only at compile time...". Dominus or Abigail will probably show up to correct me 30 seconds after I hit submit, but here goes at my explanation anyway. :)

        Normally (without prototypes), subroutines are defined at compile time. During runtime, you'll get errors about undefined subroutines. There's too much left until runtime to verify things at compile time, what with importing and AUTOLOAD and method dispatch.

        If you do something like the following -- with our without strict -- you'll get a message that indicates perl finds the construct ambiguous:

        foo; sub foo { print "Fooing!\n" }
        On the other hand, if you make it clear that foo is a subroutine and not a constant in void context, it's perfectly fine:
        foo(); &foo; # or even my $foo = \&foo; $foo->(); sub foo { print "Fooing!\n" }
        So it's not really a case of things having to be defined in the correct order because all of this happens at runtime. During compile time, Perl populates the symbol table and resolves what it can. That includes prototypes, and part of the reason seems to be so that you can use them almost as barewords just like built-in functions. That has to happen at compile time.

        Dunno if that answers your question or muddies the matter. I have only seen a couple of good uses of prototypes, and rarely even think about them.

Re: Function Prototypes
by Zaxo (Archbishop) on Jul 03, 2001 at 16:53 UTC

    The errors will go away if you move the definition of usage() above the first call of it.

    You are defining usage() with a prototype of no arguments by the empty parens before the code block. This is a good use of that because the sub is constant and can be inlined. Perl takes the "void" prototype as a signal it may do so.

    After Compline,
    Zaxo

    Update: Reply to mvaline. Yes, the reason you get warnings is that -w is in force, and the compiler is unable to apply the prototype (having seen it too late). I don't know enough about perl's innards to explain why. It is sufficient to put a declaration like sub usage(); before any call.

(crazyinsomniac) Re: Function Prototypes
by crazyinsomniac (Prior) on Nov 09, 2001 at 14:00 UTC