Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot

Perl module symbol import versus direct invocation

by JayBonci (Curate)
on Feb 26, 2003 at 07:29 UTC ( #238686=perlquestion: print w/replies, xml ) Need Help??

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

I am quite bewildered by while a particular perl module can tell the difference between when it a function is use'd into scope and when it is called directly from the module name. In this example that I gave earlier in response to a question:
#!/usr/bin/perl -w use strict; use Date::Calc qw(Add_Delta_Days); my (undef, undef, undef, $day, $month,$year) = localtime(); $year+=1900; $month+=1; ($year,$month,$day) = Add_Delta_Days($year,$month,$day, -3); print join("-", $year,$month,$day)
Works fine. But this:
#!/usr/bin/perl -w use strict; use Date::Calc; my (undef, undef, undef, $day, $month,$year) = localtime(); $year+=1900; $month+=1; ($year,$month,$day) = Date::Calc->Add_Delta_Days($year,$month,$day, -3 +); print join("-", $year,$month,$day)
Doesn't work correctly. It throws a usage warning. (Keep in mind this throws the error even if I add the qw symbol import). Perhaps, I'm wrong, but I thought that specifying the scope with ModuleName->FunctionName didn't call the function any differently or with any different parameters.

Where's the bug? My code? My reasoning? The module?
Thanks for any guidance anyone can give.


Replies are listed 'Best First'.
Re: Perl module symbol import versus direct invocation
by robartes (Priest) on Feb 26, 2003 at 07:40 UTC
    Actually, it does. Calling a function using the -> syntax calls it as an object method. The only practical distinction is that the first argument passed to the function then becomes a reference to the object (it is supplied automatically by Perl as part of the -> magic). This is probably the source of your error (though I can't be sure, not having seen the source of Date::Calc).

    Try instanstiating a Date::Calc object before calling Add_Delta_Days with -> .

    Update: You seem to be confusing fully qualifying a symbol with object calling syntax. What you want to do when you qualify a symbol with the package name is Date::Calc::Add_Delta_Days.


      Calling a function using the -> syntax calls it as an object method.
      Nope. -> has a double purpose:
      1. Object method call: $obj->meth(@params)
      2. Class method call: Class->meth(@params)
      What the OP did, is applying the latter: invoking a function intended to be used as a function, as a class method. The result is that an extra parameter is unshifted, by perl, in the argument list, @_, before control is passed to it: the Class, which is a string.

      He should try, with a higher chance of success, to call

      Date::Calc::Add_Delta_Days($year,$month,$day, -3);
        So I guess my next logical question is, why have a Class->meth() call at all, if it's not quite an Object call, and it's still not calling the function with the intended arguments? It uses a weak reference to the classname, and is likely to break things for non-OO modules.

        I suppose you could intend for your module to be used that way, but is there a sane way to test for how your module is being used, other than to always check the first parameter to make sure that it's not your classname? Or is this just a matter of "read the documentation before use"?

      Keep in mind that Date::Calc doesn't provide an oo interface. On the other hand, Date::Calc::Object does and it provides some nice overloaded operators for comparing dates.
      Actually, it's calling a class method. There's no object involved here. The first argument will be the name of the class, Date::Calc in this case.


        Exactly, this web page can help to make it more clear.
      Okay, but for instance there isn't a new method in the Date::Calc object. Wouldn't it have to auto-instantiate the object before it could call methods on itself? If it's passing a reference, what is it passing a ref to, if no object has been created?
      jaybonci@starlite:~/perl$ perl -MDate::Calc -e 'my $foo = new Date::Ca +lc;' Can't locate auto/Date/Calc/ in @INC (@INC contains: /etc/perl / +usr/local/lib/perl/5.8.0 /usr/local/share/perl/5.8.0 /usr/lib/perl5 / +usr/share/perl5 /usr/lib/perl/5.8.0 /usr/share/perl/5.8.0 /usr/local/ +lib/site_perl .) at -e line 1

        This is no longer in answer to you initial question, as dbp pointed out that Date::Calc does not provide an object interface, but I got curious as to what happens when you call a method on something that is not an object. Lessee...
        #!/usr/local/bin/perl -w use strict; package Test; print Test->method(); sub method { my $self=shift; return $self; } __END__ Test
        Ah, that's right - you get the package name. I knew this ;).

        So that answers your question: if no object has been created, calling a function with -> results in the function getting the package name as the first argument. This also explains the error in your script: Date::Calc::Add_Delta_Days gets 'Date::Calc' as the year, hence the usage message.

        Update: See bart's post below for some more information on -> syntax.


Re: Perl module symbol import versus direct invocation
by chromatic (Archbishop) on Feb 26, 2003 at 17:37 UTC

    Perl 5 doesn't really make much of a distinction between methods and functions. You can call a function as a method and a method as a function. There are two important differences:

    • methods are looked up and potentially inherited
    • methods have the invocant passed as the first parameter

    That's why Test::MockObject works -- you can call a method with the function semantics and manually pass an invocant:

    Everything::Node::node::update( $mock_node, $user );

    In your case, you're just having Perl look for Add_Delta_Days in Date::Calc or a parent class, call the nearest sub it finds, and pass 'Date::Calc' as the first argument. Since the module never planned for that, it'll pull the string into $year and that's when things break.

    Date::Calc::Add_Delta_Days( $year, $month, $day, -3 );

    No inheritance lookup, no invocant passing.

Re: Perl module symbol import versus direct invocation
by pg (Canon) on Feb 26, 2003 at 17:14 UTC
    Yes, you would have a usage problem, as the package name would be passed to the function, which the function does not expect. Try this, it will become clear:
    use p; use strict; p->abc; package p; use strict; sub abc { print "begin params\n"; print(join(",", @_), "\n"); print "end params\n"; } 1;

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://238686]
Approved by robartes
Front-paged by derby
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2023-02-05 14:14 GMT
Find Nodes?
    Voting Booth?
    I prefer not to run the latest version of Perl because:

    Results (31 votes). Check out past polls.