John M. Dlugosz has asked for the wisdom of the Perl Monks concerning the following question:

I have code like this:
use strict; ... ... foo; ... ... sub foo { ... }
and it complains that foo is a bareword, and makes me write the call as foo() instead. Now, doesn't Perl know all the defined functions on an earlier pass? Under what circumstances will it not know the name is a function?

—John

Replies are listed 'Best First'.
Re: Forward-referenceing subs
by Paladin (Vicar) on Jan 12, 2003 at 06:25 UTC
    It is during the parsing/compiling stage that it is complaining as it hasn't seen the sub declaration when it sees foo;. You can fix this by calling it as you have said above with foo(); or by predeclaring before you use it.
    use strict; ... sub foo; ... foo; ... ... sub foo { ... }
Re: Forward-referenceing subs
by MarkM (Curate) on Jan 12, 2003 at 10:20 UTC

    Additional information not provided by Paladin's correct answer:

    Perl compiles from the first token in the file to the last token in the file. It does not perform multiple passes. Any information that it has regarding expected syntax needs to have been processed before the compiler reaches the token that uses the syntax.

    In order for Perl to recognize a list operator as a subroutine call ("foo;" or "foo 1, 2, 3;"), it must know, at the point that the list operator is used, that a subroutine by that name exists. The only ways for Perl to know this, is if the function was already defined (specified earlier), or if it was predeclared ("sub foo;").

    With respect to other answers: It is usually wrong to prefix a subroutine call with '&'. The '&' prefix effectively tells Perl to 'invoke subroutine using Perl 4.x compatibility mode.' (Perl 4.x and earlier required subroutine calls to be prefixed with '&'... it was not optional) The effect is that subroutine calls that use '&' as a prefix do not have prototype processing applied to the argument list. See the perlsub manpage for more information.

      Don't forget that just calling a function as &foo; without parens will behave like &foo(@_); by passing the current @_ argument array to the function. That can be a source of subtle bugs.

      Personally, I always use parens on simple function calls. I may leave them out in method calls, but those are unambiguous anyway, both syntactically to the parser as well as visually to the programmer.

      Makeshifts last the longest.

Re: Forward-referenceing subs
by diotalevi (Canon) on Jan 12, 2003 at 06:29 UTC

    If I had to guess (and I am) it's because your error is being reported during parsing and sub foo {} hasn't been seen yet. So when foo; is encountered the parser has to make a guess at what sort of thing 'foo' is and you just didn't provide enough information.

    Additions: Ok, now that it's tomorrow and I've had some sleep I'll add more to this short comment. Actually... reading the source comments is probably a better description than I can provide so I'll copy a bit from my 5.6.1 source. This is from the intuit_method() function which is at least one place where the compiler makes it's guesses as to what is a subroutine or not. Of course, reading these descriptions it quickly becomes apparent that this

    S_intuit_method Does all the checking to disambiguate foo bar between foo(bar) and bar->foo. Returns 0 if not a method, otherwise FUNCMETH (bar->foo(args)) or METHOD (bar->foo args). First argument is the stuff after the first token, e.g. "bar".

    • Not a method if bar is a filehandle.
    • Not a method if foo is a subroutine prototyped to take a filehandle.
    • Not a method if it's really "Foo $bar"
    • Method if it's "foo $bar"
    • Not a method if it's really "print foo $bar"
    • Method if it's really "foo package::" (interpreted as package->foo)
    • Not a method if bar is known to be a subroutne ("sub bar; foo bar")
    • Not a method if bar is a filehandle or package, but is quoted with

    But then I gather that intuit_method is only called for some of the potential method DWIMery. Further reading shows that it just gets uglier and uglier. What I quoted was probably the most straightforward portion.


    Fun Fun Fun in the Fluffy Chair

      you wrote :
      sub foo {} hasn't been seen yet
      that means if you put the sub foo {} at the beggining of the source, everything would be ok!?

        Sure it'd work. But this just illuminates why it's a good idea to indicate that you mean to call a function by putting the parentheses on the end. Method calls are different though and have different rules so don't confuse the two.


        Fun Fun Fun in the Fluffy Chair

Re: Forward-referenceing subs
by Coruscate (Sexton) on Jan 12, 2003 at 10:26 UTC

    The best way to avoid this type of 'accident' is to call your subroutines with a pair of parentheses. Yes, you can use the '&' symbol to call your subroutines (ie: &foo;), but IMO it makes things uglier. IIRC, the & symbol is a depreceated method of calling a subroutine. Yes, it's easy to see that you are calling a custom (not a core) subroutine, but it clutters code.

    Because everybody here cares so much, here's my favorite (and long-time) way of writing up scripts. Personally, I always put my subroutines at the top, write up a main() sub (like C/C++ which I have never used), and call main() at the bottom. I always use parentheses to call my subs, whether I am passing arguments or not.

    #!perl -w use strict; sub main { print "Welcome to my program!\n"; my ($name, $email) = ( get_input('Your Name'), get_input('Your Email Address') ); say_hello($name, $email); } sub get_input { my $msg = shift; print $msg, ': '; chomp( $_ = <STDIN> ); return $_; } sub say_hello { my ($name, $email) = @_; print "Hello $name, I have sent mail to $email!\n"; } main();

      You should note that your proposed solution (using Perl in a C-like fashion with a main() function) does not actually aid the compiler in any way.

      The compiler compiles all tokens in sequence from the first to the last. Certain constructs, such as 'BEGIN{...}' or 'use ...;' are executed as soon as they finish compiling, and cause the compiler to recurse, while other constructs such as "sub NAME ..." generate symbol table entries as soon as they finish compiling.

      Your code defines the symbol 'main' (perhaps confusing, given that the fully qualified name is 'main::main'), uses the symbols 'get_input' and 'say_hello'. Then defines the symbol 'get_input' and 'say_hello'. At the very end, the compiler terminates and the execution phase begins. The first executable statement is 'main()'.

      Definately, choosing to always invoke subroutines using () over using list operator syntax, will avoid this particular problem. The problem that it does not avoid, is the situation where a subroutine is invoked, but later prototyped:

      a(@a); sub a ( \@ ) { my($array_reference) = @_; }

      If -w is not used, Perl is perfectly happy to execute the above code generating undesirable results ($array_reference is assigned the first value in @a). If -w is specified, Perl generates the warning message:

      main::a() called too early to check prototype at ...

      Moral of the story: If you use prototypes at all, make sure to always pre-declare your subroutines using "sub NAME (PROTOTYPE);". However, if you have read about the pitfalls regarding prototypes, you may decide that it is reasonable to completely avoid using prototypes at all, in which case, always using () when invoking subroutines will eliminate the problem described by the original poster (list operator not recognized).

      Secondary moral of the story: -w can be extremely useful.

      Yes, you can use the '&' symbol to call your subroutines (ie: &foo;), but IMO it makes things uglier.

      Not only does it make it uglier, it also doesn't do the same thing. The issue is covered in perlfaq7, "What's the difference between calling a function as &foo and foo()?". I pointed out the very same thing in Re: Hash of Hash of Listed subroutines but then in the context of dereferencing subroutines. For some reason, it's much more common to drop the parenthesis when dereferencing than when making a regular subroutine call.

      ihb
Re: Forward-referenceing subs
by osama (Scribe) on Jan 12, 2003 at 09:35 UTC

    I always prefer to use foo(), that way I always know it's a sub.

    I remember using &foo; many many years ago

Re: Forward-referenceing subs
by particle (Vicar) on Jan 13, 2003 at 14:30 UTC

    an explanation is in the docs, perhaps a little obscured. from perl 5.8.0's perlsub SYNOPSIS:

    <snip>To declare subroutines:

        sub NAME;			  # A "forward" declaration.
        sub NAME(PROTO);		  #  ditto, but with prototypes
        sub NAME : ATTRS;		  #  with attributes
        sub NAME(PROTO) : ATTRS;	  #  with attributes and prototypes
        ...
    
    </snip>

    and

    <snip>to call subroutines:

        NAME LIST;	   # Parentheses optional if predeclared/imported.
    
    </snip>

    ~Particle *accelerates*