Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Sub calling sadness

by nefigah (Monk)
on Mar 08, 2008 at 06:26 UTC ( [id://672938]=perlquestion: print w/replies, xml ) Need Help??

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

I've seen warnings in the docs/on PM/in books about how to call functions, and it finally bit me in a weird way.

Oddly, I recall someone saying that user-defined functions SHOULDN'T be called using & (and if you do use it, to make sure you use parentheses).

That sounded good to me, so I was avoiding using & and (), when I ran into this sort of scenario (in my unit test file):
use Test::More 'no_plan'; require 'some_file_with_my_functions.pm'; my $foo = "hi"; my $bar = " hi"; ok( ThatPackage::blah $foo, 'blah' ); ok( ThatPackage::blah $bar, 'blah2' );

(Names changed to protect the innocent.)

So I get an error at the blah2 test, (like, not the test failing, but a compile error) and was very confused.

Well, putting parentheses thusly fixed it:
ok( ThatPackage::blah($bar), 'blah2' );

Which is fine and dandy, but makes me somewhat sad because I don't understand why that's necessary just because the stupid string in $bar has leading whitespace. :(

I don't suppose some kind monk could make sense of it for me?

I'm a peripheral visionary... I can see into the future, but just way off to the side.

Replies are listed 'Best First'.
Re: Sub calling sadness
by John M. Dlugosz (Monsignor) on Mar 08, 2008 at 11:33 UTC
    Wow, lots of varied answers.

    Let me distill the correct answer from the various posts.

    ThatPackage::blah is not defined as a sub when the call to ok is compiled, because you coded require instead of use. I don't know if that is something else you should look into, or an artifact of your testing framework.

    I'm not sure, but I think use strict 'refs' would spot the problem. Why don't you have use strict at the top of your file?

    So, the contents of $bar is taken as a package name at run-time (think new Blah; vs. $x="Blah"; new $x;), and the white space is a problem at this time. I don't know why it spotted it at "compile time" unless it has something to do with the constant optimizer.

    Anyway, change the require to use, and then it will behave as greedy arguments to a function call without parens, since it knows that is a function.

    —John
    writing from 西安 (Xi'an), China

    Edited 10-March re correction from ikegami (writing from 昆明 (Kunming))

      Small correction:
      "So, the contents of $bar is taken as a method name at run-time"
      should be
      "So, the contents of $bar is taken as a class name or object reference at run-time" (ThatPackage::blah would used as the method name: <<Can't call method "ThatPackage::parse" without a package or object reference>>)

      Awesome, it all makes sense now. This was my first time using my own functions from another file, and I wasn't sure if it was safe to use use without defining export lists and whatnot, so I just did require. In light of this I changed it to use, and it works, and revealed the problems you all have been talking about, just like you guys said. Many thanks!


      I'm a peripheral visionary... I can see into the future, but just way off to the side.
Re: Sub calling sadness
by ikegami (Patriarch) on Mar 08, 2008 at 07:09 UTC

    ok( ThatPackage::blah $foo, 'blah' );
    means
    ok( ThatPackage::blah($foo, 'blah') );

      ok( ThatPackage::blah $foo, 'blah' ); means ok( ThatPackage::blah($foo, 'blah') );
      Alright. Perl must fairly liberally interpret it sometimes; because it was working as ok( ThatPackage::blah($foo), 'blah' ) until $foo contained leading whitespace :( (I could tell because the ok() method was correctly printing out 'blah' as the test description)


      I'm a peripheral visionary... I can see into the future, but just way off to the side.
        Update: I wrote the below, obviously after reading ikegami's answer above. Yet, I went on, totally wrong. The only problem with his answer was that it's a bit terse. When the sub you are calling eats the rest of the argument list, you get surprises. For example, look at print. It seems a litle silly that ok() is OK with only one argument, but it is, which hides the real problem in your code.
        sorry for confusing... (e.g.:disregard the rest of this post)

        It is not possible to explain the semantics of your code without access to the definition of ThatPackage. If you could include that definition, we could probably better explain what happens and why.

        For example, include your definition of ThatPackage::blah something like this (after verifying that it still demonstrates the problem):

        use Test::More 'no_plan'; #require 'some_file_with_my_functions.pm'; package ThatPackage; sub blah { return $_[0] =~ /hi/ }; # Does NOT demonstrate the problem package main; my $foo = "hi"; my $bar = " hi"; ok( ThatPackage::blah $foo, 'blah' ); ok( ThatPackage::blah $bar, 'blah2' ); ok( ThatPackage::blah($foo), 'blah3' ); ok( ThatPackage::blah($bar), 'blah4' );
        cheers
Re: Sub calling sadness
by pc88mxer (Vicar) on Mar 08, 2008 at 07:04 UTC
    Update: For the complete story on this question, please see John's answer below. The subtlety is that perl's interpretation of the function/method call depends on whether or not the subroutine is defined when the call is compiled.

    The syntax:

    ThatPackage::blah $foo
    is the method-object calling syntax. For instance, consider:
    my $baz = []; bless $baz, "ThatPackage"; ok( blah $baz, 'blah-baz');
    This will call ThatPackage::blah with first argument of $baz using object method dispatching. The object is expected to be a blessed reference (which is generally the case) or it can also be a package name. When the method is a fully qualified identifier (like ThatPackage::blah), perl will start looking in that specified package for the subroutine to execute (see the MyCritter example in man perlobj.) However, even in this case the object still must be either a blessed reference or an package name - although perl does not check to see if the package actually 'exists.' Since spaces are not allowed in package names you are getting an error when calling ThatPackage::blah $bar.

    By contrast, the syntax: ThatPackage::blah($bar) is simple function calling syntax. In this case the subroutine ThatPackage::blah must be defined or an error will be raised.

    When using method-object syntax I would say that verifying that the object at least looks like an object is a useful check to make sure that you're doing what you think you're doing.

      This will call ThatPackage::blah with first argument of $baz using object dispatching

      "Object dispatching?" No, ThatPackage::blah $foo is not an indirect method call if ThatPackage::blah has been declared as a sub. It's a simple function call.

      If sub blah didn't exist in ThatPackage, then it would be an indirect method call, but $baz would be used as the class name, not as an argument.

        My point is simply that when you use the syntax ThatPackage::blah $foo, perl treats it as a method invocation and expects $foo to look like an 'object' (either a blessed reference or a package name), and this is why the OP is getting the error.
      As a Perl noob, I haven't even opened the Object can of worms yet. I was merely trying to call a function defined in a different file... I suppose that means I have to use the 'function calling syntax' (with the parentheses)--i.e., parentheses there are never optional?
      Thanks!


      I'm a peripheral visionary... I can see into the future, but just way off to the side.
Re: Sub calling sadness
by FunkyMonk (Chancellor) on Mar 08, 2008 at 11:12 UTC
    require isn't executed at compile time and if it was your problem goes away.

    Either wrap your require in a BEGIN block, or use some_file_with_my_functions instead.

    BEGIN {require 'some_file_with_my_functions.pm' } #or use some_file_with_my_functions; # you may need to "use lib '.'"

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://672938]
Approved by pc88mxer
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (5)
As of 2024-03-19 10:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found