Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

$object->UnrelatedPackage::some_subroutine()

by Thilosophy (Curate)
on Feb 18, 2005 at 03:09 UTC ( #432172=perlmeditation: print w/ replies, xml ) Need Help??

I just discovered (thanks to diotalevi for pointing me at it) an arcane (?) but possibly useful feature of Perl's object method calling syntax: You can specify a fully qualified (including the package) name for the method.

package SomeDatabaseStuff; sub my_funny_sql{ my ($dbh) = @_; $dbh->do('my great query'); }

You (or at least I) have until now called the subroutine (note that it is not even intended to be a method at all) like so

my_funny_sql($dbh);

But it can also be called like this:

$dbh->SomeDatabaseStuff::my_funny_sql();

This is especially nice if you have additional parameters that you want to visually seperate from $dbh:

$dbh->SomeDatabaseStuff::my_funny_sql ( 'some parameter', 12 , 34 );

Note that this syntax can only be used when $dbh is indeed a blessed reference (although its class seems to be not involved in the "method" lookup anymore), and if the name of subroutine you want is fully qualified (otherwise the normal method lookup will occur, starting at the package of $dbh)

This even works in combination with @ISA-inheritence (although the search starts at the package of the subroutine, not the package of the object as usual):

package MoreDatabaseStuff; @MoreDatabaseStuff::ISA = qw( SomeDatabaseStuff); # no subroutines here $dbh->MoreDatabaseStuff::my_funny_sql(); # ends up being dispatched properly # to the sub in the parent SomeDatabaseStuff

All this is probably mentioned in the Perl OO docs, but it was new to me.

Update: I forgot to point out the important detail that $dbh is a DBI connection handle (and not something blessed into SomeDatabaseStuff).

my $dbh = DBI->connect('....'); $dbh->SomeDatabaseStuff::my_funny_sql;

Comment on $object->UnrelatedPackage::some_subroutine()
Select or Download Code
Re: $object->UnrelatedPackage::some_subroutine() (not for me)
by tye (Cardinal) on Feb 18, 2005 at 05:13 UTC

    Interesting. I was just trying to use that a couple of days ago. It didn't work on the several platforms I tried, though I rarely have 5.8 or later to use anywhere:

    $ perl -e "Lie->Pkg::Meth()" Can't locate object method "Meth" via package "Pkg::Meth" at -e line 1 +. $

    Notice it tried to look for Pkg::Meth::Meth() not Pkg::Meth().

    No, I haven't looked any further. It was easy enough to work around, either as you noted or, better, using can(). And, no, it didn't work with a blessed object any better than it did with a class name.

    Update: The two copies of Perl I have handy right now are both 5.6.1 (Zaurus Linux and FreeBSD) and they both have this bug.

    - tye        

      Hmm. Your example works for me ( v5.8.1-RC3 built for darwin-thread-multi-2level):
      $ perl -e 'Lie->Pkg::Meth()' Can't locate object method "Meth" via package "Pkg" (perhaps you forgo +t to load "Pkg"?) at -e line 1.

      Is this a new or unstable feature?
      I checked 5.8.1-RC3 (works), 5.8.0 (works), 5.6.1 (works).

      And contrary to what I thought, you do not have to use a blessed reference, a package name is fine as well. It also works with a string scalar:

      $ perl -e '$a = "Lie"; $a->Pkg::Meth()' Can't locate object method "Meth" via package "Pkg" (perhaps you forgo +t to load "Pkg"?) at -e line 1.

      But not with other types of parameters (that cannot qualify as class name or object instance):

      $ perl -e '$a = []; $a->Pkg::Meth()' Can't call method "Pkg::Meth" on unblessed reference at -e line 1. $ perl -e '$a = 123; $a->Pkg::Meth()' Can't call method "Pkg::Meth" without a package or object reference at + -e line 1.
      The error message is wrong (in version 5.6.1), but the feature works perfectly well if you call a method that really exists:
      perl -e 'package Pkg; sub Meth{print "hello\n"} package main; Lie->Pkg +::Meth'
      hello
      

        The root cause was probably my previous misunderstanding at how Apache::DBI and DBI are related. I didn't look at the failure much after producing the above test case because the work-arounds were too easy.

        Thanks.

        - tye        

Re: $object->UnrelatedPackage::some_subroutine()
by itub (Priest) on Feb 18, 2005 at 14:21 UTC
    Here's what perlobj says:
    If you need to, you can force Perl to start looking in some other package:
    my $barney = MyCritter->Critter::find("Barney"); $barney->Critter::display("Height", "Weight");

    Here "MyCritter" is presumably a subclass of "Critter" that defines its own versions of find() and display(). We haven't specified what those methods do, but that doesn't matter above since we've forced Perl to start looking for the subroutines in "Critter".

    As a special case of the above, you may use the "SUPER" pseudo-class to tell Perl to start looking for the method in the packages named in the current class's @ISA list.

    Personally I don't like the style you are suggesting, because the use of this syntax suggests that DBI is a subclass of SomeDatabaseStuff (which would be a class, with my_funny_sql being a method), causing confusion.

Re: $object->UnrelatedPackage::some_subroutine()
by stvn (Monsignor) on Feb 18, 2005 at 14:39 UTC

    Interesting yes, but IMO an all around bad idea. Not only does it cause confusion as to what $dbh is, it also causes confusion as how the SomeDatabaseStuff package fits into everything. As far as I am concerned, this is basically only useful as an obfuscation technique, and should never be used in real code.

    *sigh* and people wonder why Java programmers think perl is not really OO (as if Java was really pure OO too, but that is another discussions all together).

    -stvn
      So I should stop using SUPER and should definitely avoid TheDamian's NEXT?

      While I agree that it should not be casually used, there are cases where I find this feature useful. And so I wouldn't categorically say that people shouldn't use it.

        So I should stop using SUPER and should definitely avoid TheDamian's NEXT?

        Of course not.

        SUPER:: is part of perl's OO system, and a built in pseudo-package. So as far as I am concerned, it is a different story.

        As for NEXT, thats up to you if you want to use it. No doubt that TheDamian knows what he is doing, but that's a pretty crazy module. Personally I just try to avoid designing anything which would need it in the first place.

        However, what the OP was actually talking about was basically abusing a hole in perl's module/object system (at least thats what I see it as). The OP is actually talking about bascially using this to allow any random blessed object to become the first argument in a function, not a method. This is different from the controlled method dispatching of SUPER and NEXT.

        -stvn
      Interesting yes, but IMO an all around bad idea. Not only does it cause confusion as to what $dbh is, it also causes confusion as how the SomeDatabaseStuff package fits into everything. As far as I am concerned, this is basically only useful as an obfuscation technique, and should never be used in real code.

      Hmm. I was going to mention this pattern in the next version of DBIx::ProcedureCall. That module gives you auto-generated wrapper subroutines for database stored procedures. It does not use object orientation, just creates plain old functions. All these functions take a DBI handle as their first parameter:

      # create wrapper subroutines for the Oracle # PL/SQL package MyPackage use DBIx::ProcedureCall qw ( MyPackage:package ); # call a function in that package # (passing in the DBI handle to use) my $result = MyPackage::my_function( $dbh, 123, 456);

      I am unhappy with having to pass in $dbh every time. In my own use of the module I have some custom code to obtain the handle automatically, but this is application-specific and cannot be included in the module (although the module could be refactored a little to allow everyone to extend it in this fashion).

      So I was thinking to use the strange syntax we are currently discussing to at least visually separate $dbh from the "real" parameters (that get passed to the subroutine). This probably also helps as a reminder not to forget that first parameter.

      my $result = $dbh->MyPackage::my_function( 123, 456);

      Of course, this looks like a method call on $dbh, which it is not. There is really no OO going on here, although it does look like it.

      On the other hand, OO considerations aside, I liked the way how this makes calling a stored procedure look similar to doing a select statement (or other DBI operations).

      my $result = $dbh->selectrow_arrayref('select * from blah');

      I'll probably drop the idea because the syntax is too confusing.

        Thank you for dropping it.

        If you really want to avoid passing in the dbh all the time, you're crying out for an object. Your object would more or less just store the dbh (maybe there's other things, too, that make sense for your package, I don't know, I don't use Oracle). Then it would be called via $obj->my_function(123,456) as the $obj created would be, presumably, blessed into MyPackage. I'm sure someone here could help with the design in more detail.

        If I were ever to use Oracle, and I happened upon your module, and you were asking people to use this style, I would have serious doubts as to the reliability of the module, and, if I were to use it anyway, I sure as heck would not be using this syntax. It really is, IMO, that bad.

        Now, if someone were to use it in a complex, multi-package obfu, that would be different. "Can you trace this program without running it through the debugger or the deparser?" Here the goal is unreadable code. But my production code using your module ... that needs to be maintainable, and $dbh->Mypackage::my_function(123, 456) is not it.

        (Of course, I'm also quite partial to object wrappers around the dbh object ... having put one of those on CPAN myself ;->)

Re: $object->UnrelatedPackage::some_subroutine()
by Courage (Parson) on Feb 18, 2005 at 17:45 UTC
    More than that: it is quite common for me to use $widget->$methodname(@parameters); inside Tcl::Tk code.

    Initially I used "eval" to find out method name but was very glad to discover this nifty feature, which makes implementation faster, strictier and safer.

    In my case there were some non-trivial places with SUPER and inheritance due to heavy AUTOLOADING with further defining of newly created subroutine, but those were easy to implement
    :)

      Random obscure trick for you:
      my $obj = bless {}; my $method_name = sub {"Just another Perl hacker,\n"}; print $obj->$method_name();
      I've used this when dealing with code that used the above trick to get a custom result without having to go and create a special method for it.

      Incidentally if you're using heavy AUTOLOADING, then you're probably better off assigning closures to typeglobs and getting rid of most of your AUTOLOADs. Not necessarily, but it tends to work well in my experience.

        I've used this when dealing with code that used the above trick to get a custom result without having to go and create a special method for it.

        This is fine for a quick and dirty solution, but I would be wary of using it for anything else.

        Perl's object system is somewhat broken as it is, so abusing it like this is just (IMO of course) a bad idea.

        -stvn
        Thanks for that knowledge bit.

        In my particular case this trick will not mess a program, because I use it inside AUTOLOAD so coderefs should not pass through.

        But...let's see, you can call

        $Tcl::Tk::Widget::AUTOLOAD=sub{print 'tricky hacky sub'}; Tcl::Tk::Widget::AUTOLOAD($object)
        Accidentally, it still not pass through as in that AUTOLOAD I see:
        my $method = $Tcl::Tk::Widget::AUTOLOAD; # Separate method to autoload from (sub)package $method =~ s/^(Tcl::Tk::Widget::((MainWindow|$ptk_w_names)::)?)// or die "weird inheritance ($method)";
        But I get your point: I should closer revise that module for similar things.

        Also, in my case, in Tcl::Tk module AUTOLOAD is used to redirect a method to Tcl/Tk system, so it is not OO trick but rather some kind of redirecting methods to Tcl/Tk.

        PS. I was talking about Tcl::Tk as I do not have anything other resembling OO

Re: $object->UnrelatedPackage::some_subroutine()
by ihb (Deacon) on Feb 21, 2005 at 12:31 UTC

    I use the fat comma.

    _foo($self => $a, $b);
    Works well for me.

    ihb

    See perltoc if you don't know which perldoc to read!

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://432172]
Approved by Tanktalus
Front-paged by Courage
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (9)
As of 2014-10-01 07:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (389 votes), past polls