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

The following code:

#!/usr/bin/perl -w use strict; use Tk; # use Tk qw( exit ); # Also produces same error. exit main( @ARGV ); sub main { # This part doesn't matter }
produces:
Argument "main" isn't numeric in subroutine entry at tk.pl line 6.
It appears that somehow Tk is overriding the exit() built-in in a way that doesn't define exit() as a function so that Perl interprets exit main( @ARGV ) as an "indirect object" thingy of the form "bareword bareword( args )", that is, "method package( args )", and calls "main"->exit( @ARGV ), that is, main::exit( "main", @ARGV ).

Note that you can fix the problem by changing the one line to:

exit( main( @ARGV ) );
(or by commenting out the use Tk line).

All I've found in Tk's Perl source code that appears relevant is:

use base qw(Exporter DynaLoader); @EXPORT = qw(Exists Ev exit MainLoop DoOneEvent tkinit);
There is no exit() function defined anywhere that I can find. Tk uses AutoLoading but it doesn't appear that exit() is autoloaded. So exit() must be an XS subroutine?

Any more clues as to what is going on here? Is there something that Tk could do differently to prevent this (minor) problem [other than rename Tk::exit() and provide a new Tk::exit() that is a Perl wrapper for the renamed XS function]? Or is there a change to the XS subsystem that would "fix" this?

        - tye (but my friends call me "Tye")

Replies are listed 'Best First'.
Re: Tk: exit main(@ARGV); fails
by Fastolfe (Vicar) on Nov 08, 2000 at 22:16 UTC
    It looks to me like you're declaring main after you use it. Since you're not doing &main, and main isn't defined yet, Perl might be stringifying it, thus generating the error you see.

    Try using an &, or declare main before you use it.

    Update: After verifying that what I was saying above didn't make 100% sense (as I tested what you were doing with my own arbitrarily named functions and it worked), I've been looking at the source for the Tk stuff for a while and have been unable to locate where this function is even defined! The only reference to it is in TkXSUBS.def, but it's commented out in the source I downloaded. I can't find any reference to Tk::exit or 'exit' in an .xs file anywhere. Goofy, but I don't claim to be an XS expert.

    Just use Tk (); or explicitely name what you want exported. That should leave Tk::exit in Tk's namespace.

      Thanks for the nudge in the right direction. The crux of the problem is that the imported exit() does not have a prototype and overrides the built-in exit() which has a prototype of ($) [takes exactly one scalar argument].

      I'm really starting to wish for a

      use strict "object"
      pragma to disallow the "indirect object" syntax such as:
      my $obj= new Neural::Net( "adaptive" );
      which is already heavilly discouraged by many.

      I knew that < exit &main( @ARGV ) > would fix the problem because "&main" is no longer a bareword. Finding that declaring "sub main" also fixed it got me wondering.

      Since normally the parens in "main( @ARGV )" are clearly enough to tell Perl that "main" is a subroutine (you may need an & to tell Perl that you want your subroutine and not some built-in with the same name), the fact that "exit main( @ARGV )" always worked for me convinced me that I wasn't being ambiguous.

      But it appears that exit() being a function isn't enough to cause Perl to interpret "exit main( @ARGV )" as "exit( main(@ARGV) )". But having "sub exit($);" is enough.

      This confuses me because I thought one of the big problems with the indirect object syntax was:

      package Widget; use WingNut; sub new { # Doesn't matter } sub Method { my $self= shift( @_ ); $self->{SubObj}= new WingNut(@_); # oops!! }
      because that last line would call Widget::new() instead of WingNut::new(). But it "works" for me. Oh well.

              - tye (but my friends call me "Tye")
      This is unlikely the problem. saying func() with the parens like that is enough for the compiler to note that func is a subroutine. It doesn't matter where you declared it because all subroutines are package scoped and compiled before runtime. Also, the error for using an undeclared subroutine is different from the one that Tye got.

      It looks to me like something is up with exit wherein it has been defined with the expectation that it gets a number. Hmmmm Tye, did you try having main return 1?