Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

AUTOLOAD - the good, the bad, and the ugly

by shemp (Deacon)
on Oct 14, 2004 at 18:13 UTC ( [id://399289]=perlmeditation: print w/replies, xml ) Need Help??

This post is in response to all the very interesting responses i got to my recent AUTOLOAD post: AUTOLOAD cascade

Basically I'm trying to get an understanding on what people use AUTOLOAD for in general, and what is considered good practice (holy war to follow). There are a lot of *interesting* things that can be done with AUTOLOAD, but as i get deeper, i keep finding conflicting opinions / reasons as to AUTOLOAD or not to AUTOLOAD.

It's a nice timesaver to use it to handle simple accessor / mutators without having to write them explicitly:

package some_package; ... { my %simple_data = ( 'name' => 1, 'age' => 1, ... } sub AUTOLOAD { my $self = shift; (my $method) = $AUTOLOAD) =~ s/.*:://; return if $method eq 'DESTROY'; if ( exists $simple_data{$method} ) { if ( defined $_[0] ) { $self->{$method} = $_[0]; } return $self->{$method}; } } }
But if you're inheriting from this class, you definitely need to know too much detail about the implementation, particularly that its using AUTOLOAD for some accessor / mutators.

As was sort of talked about in my other thread, perhaps a better way to do this is along the lines of:

package some_package; ... { BEGIN { my @simple_data = qw(name age ...); no strict 'refs'; foreach my $data (@simple_data) { *{$data} = sub { my $self = shift; my ($value) = @_; if ( defined $value ) { $self->{$data} = $value; } return $self->{$data}; } } use strict; }
This way, these accessor / mutators are in the symbol table, and will be looked up faster, will be found by can(), etc. This avoids the inheritance problem from the other post too.
What else do people use AUTOLOAD for? I have used it as a delegator if an object will contain a collection of other objects, if the circumstances are correct.

Perhaps part of my problem is that a lot of my ideas come from Damian Conways 'Object Oriented Perl' (Manning 2000), which is perhaps outdated.

Or maybe AUTOLOAD can be used for a lot of neat tricks in little scripts, but becomes quite annoying for large software projects.

Replies are listed 'Best First'.
Re: AUTOLOAD - the good, the bad, and the ugly
by chromatic (Archbishop) on Oct 14, 2004 at 18:31 UTC

      I think what chromatic means to say is that you can use the subs pragma to avoid the symbol table issue you spoke of in the third from last paragraph. The subs pragma will create stub (no-op) subroutines at compile time which you can then fill in with AUTOLOAD when they are needed.

      hmmm maybe only the 'u', 's', 'e', 'b' and ';' keys are working on chromatic's keyboard ????

      -stvn

        The square brackets work too. :)

Re: AUTOLOAD - the good, the bad, and the ugly
by stvn (Monsignor) on Oct 14, 2004 at 19:19 UTC
    It's a nice timesaver to use it to handle simple accessor / mutators without having to write them explicitly

    To start with, IMO good OO design is not making an accessor/mutator for all your object fields. I almost never make accessor/mutator functions like you show. Since some values should be read-only (only accessor), and IMO mutators should not mearly be means of setting object fields, but should be tied to the behavior of the object instead.

    Perhaps part of my problem is that a lot of my ideas come from Damian Conways 'Object Oriented Perl' (Manning 2000), which is perhaps outdated.

    The problem could also be that Damian is insane!!! Personally I love that book, but he sometimes goes over the edge telling you all the insane stuff which can be done, but probably shouldn't. When I had my junior programmers reading that book, I told them specifically to skip most of the middle of the book since it was just full of strange tricks which we would likely never use (of course they were free to read it if they wanted, but I forbade them to use that knowledge without really really really good justification).

    Or maybe AUTOLOAD can be used for a lot of neat tricks in little scripts, but becomes quite annoying for large software projects.

    My feelings is that AUTOLOAD is a tool for which there are only a few good uses, and those are really fringe cases which will very rarely come up in real world coding scenarios.

    For instance the NEXT module would not be possible without AUTOLOAD and IMO that is a excellent usage of it. I recently answered a question about dispatching SUPER calls to mix-ins which used AUTOLOAD (and was very much inspired by the code in NEXT). In Class::Trait::Base I used AUTOLOAD to make sure that calls to SUPER:: were being dispatched correctly, and I think Class::Role && Class::Roles do similar things.

    I feel these are justified usages of AUTOLOAD, since there really is no other way to accomplish them without AUTOLOAD. I do not think it is a justified usage of AUTOLOAD to save typing time (auto-created accessors/mutators and delegation), since I think many times that leads to overly clever code which is a pain to maintain and many times impossible to extend (ie - subclass).

    However, these are all purely my opinions, and to be taken with a HUGE grain of salt.

    -stvn
      Actually, I think your opinions are well-reasoned. AUTOLOAD is kinda like a number of other Perl features - it's very cool, but serves to provide abilities that comes up 1% of the time. In that 1%, the feature is absolutely critical. However, using the feature outside of that 1% is actually detrimental.

      Another feature I think belongs in this list (and is related to AUTOLOAD) is symbol-table manipulation. It's very cool, but should be avoided in most situations. (Yes, I know that a lot of stuff is done via symbol-table manipulation, but that's using the API.) tie is another feature that, imho, belongs in this category.

      Basically, the question is really "Should I use the published API or muck about in the internals?" 99% of the time, the API is good enough. While having the ability to do what needs done in the other 1%, most programmers aren't disciplined enough to not use it when it's not appropriate.

      I'm not arguing for a Java- or VB-ification of Perl. I'm arguing for some self-discipline among Perlers.

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

        Another feature I think belongs in this list (and is related to AUTOLOAD) is symbol-table manipulation. It's very cool, but should be avoided in most situations. (Yes, I know that a lot of stuff is done via symbol-table manipulation, but that's using the API.) tie is another feature that, imho, belongs in this category.

        I agree on both of these items as well. And while personally I do like mucking around with the symbol table, I try to do with great respect for the power it gives me and not to abuse it for the sake of just being clever. As for tie, I have only ever used it once, and much like my uses of AUTOLOAD, there was not other way to accomplish the same thing by other means.

        I'm not arguing for a Java- or VB-ification of Perl. I'm arguing for some self-discipline among Perlers.

        I don't take your statements to be that at all, I see your case as one for rational restraint and only going to war,.. ahem I mean symbol tables/AUOTLOAD/tie if you have to.

        -stvn
        Should I use the published API or muck about in the internals?

        I've been thinking about this for a couple of days now, to give sanity the chance to overrule my insanity, but it hasn't.

        sub AUTOLOAD{}, $AUTOLOAD and tie are as much APIs as use base;, @ISA and bless.

        Both sets of function employ symbol table manipulation and 'magic'. You're being selective about which set you choose to ordain and which you choose to deprecate.

        I'm not arguing for a Java- or VB-ification of Perl.

        Actually, I think you are.

        I'm arguing for some self-discipline among Perlers.

        This sounds like the same argument as that put forward by those who vote to enforce helmet laws on motorcyclists, even though they have never ridden a motorcycle. The phrase that comes to mind is "The nanny state".


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
      Don't get me wrong, im only making simple accessor / mutators for those pieces of data that only need them, and not something more complicated. There are plently of other methods that are hand crafted - many complicated accessors / mutators. As my job is mostly data warehouse work, i end up with classes that mess with a lot of data.

      Damian is insane
      I'm beginning to think that myself, as his *interesting* ideas begin to bite me more and more.

Re: AUTOLOAD - the good, the bad, and the ugly
by Fletch (Bishop) on Oct 14, 2004 at 18:58 UTC

    Not exactly a direct answer to your question, but rather than using AUTOLOAD to handle accessors I tend to use Class::MethodMaker, which has the advantages of both declaring what the accessors are and not having to write the actual accessor code.

    Update: Gah, cleaned up after premature posting due to hitting the wrong button.

      Or consider Class::MakeMethods which gives you your choice of definition styles:
      # Explicit use Class::MakeMethods 'Standard::Hash::scalar' => [ qw/ method names / ]; # Autoload use Class::MakeMethods::Autoload 'Standard::Hash::scalar'; # Attributes use Class::MakeMethods::Attribute; sub name :MakeMethod('Standard::Hash::scalar');
Re: AUTOLOAD - the good, the bad, and the ugly
by tilly (Archbishop) on Oct 15, 2004 at 02:39 UTC
    For a longer discussion of some of the complications with AUTOLOAD (particularly how it interacts or doesn't with can), see Why breaking can() is acceptable.

    Furthermore note that Perl 6 doesn't look like it will solve the issue (it will offer an AUTOLOAD fully as problematic as the current one), but it will give alternatives to AUTOLOAD that can let people get the functionality that they want from AUTOLOAD without causing problems for can, multiple inheritance, etc. Of course that only helps you if you use those alternatives...

Re: AUTOLOAD - the good, the bad, and the ugly
by raptnor2 (Beadle) on Oct 15, 2004 at 02:56 UTC
    I've used it to wrap classes that I wouldn't know anything about, but needed to provide add-on methods for component management. Using this technique, I don't have to care what someone wants to use as a component (as long as it's a class).

    A snippet from IOC::Lite follows:

    sub AUTOLOAD{ my($self, @args) = @_; my @method_and_structure = split m|\:\:|, $AUTOLOAD; my $method = $method_and_structure[@method_and_structure-1]; if ($self->{object}->can($method)){ return $self->{object}->$method(@args); } die ">$method is not found on " . $self->get_type() . "\n"; }

    I've taken the concept a little further, almost AOP like, in the version of IOC::Lite I'm working on now. That way I can add all types of features to objects the container doesn't own. The basic component management methods will be first, followed closely by dynamic logging. Not sure where I'll head from there.

    Sorry if this is just rambling. Bottom line: I think it would be quite useful on large software projects. I can't tell you how many times I wished I had this feature when coding in (C/C++/Java/etc)

    Cheers,

    John

    janitored by ybiC: Replace frowned-upon <pre> tags with Monastery-standard <code> tags

      A nit.
      my $method = $method_and_structure[@method_and_structure-1];
      is better written (and slightly faster) as
      my $method = $method_and_structure[-1];

      But, most examples I've seen tend to do the one of the following:

      my $method = (split '::', $AUTOLOAD)[-1]; #### my ($method) = $AUTOLOAD =~ /([^:]+)$/; #### (my $method = $AUTOLOAD) =~ s/.*:://;

      In that last, you want to use .* as opposed to .*? because you want it to be as greedy as possible.

      Update: Fixed slice to scalar access.

      Update: Added parentheses in second-to-last example.

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

        I tend to do my ($method) = $AUTOLOAD =~ /.*::(.*)/s; which I find nice and clean.

        ihb

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

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-04-24 06:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found