in reply to goto and AUTOLOADed methods

I'd like to make a quiet protest on behalf of all the programmers who come into a project 4 years into it and who have to deal with the abysmal dreck that is AUTOLOAD. I have never once, and I mean never, have come across an AUTOLOAD whose existence was justified. Ever. Most of the time, it's an attempt to circumvent proper encapsulation and is a perfect example of false Laziness. Something like:
sub AUTOLOAD { my ($self, $method_name) = @_; $self->{$method_name} = $_[0] @_; return $self->{$method_name}; }
Why is this bad? Oh, let me count the ways!
  1. No checking, either compile or runtime, for typos.
  2. You can create members on the fly.
  3. $self->FooBar and $self->foobar are different.
  4. There is a much cleaner WTDI, using a base class that will receive a list of attributes to use and auto-generate your getters/setters/mutators for you. This option even has the benefit of being self-documenting and provides runtime checking for typos.
Would someone please give me a place, in production code, where AUTOLOAD shines over proper decomposition?

------
We are the carpenters and bricklayers of the Information Age.

The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Replies are listed 'Best First'.
Re: Re: goto and AUTOLOADed methods
by ctilmes (Vicar) on Aug 01, 2003 at 13:38 UTC
    I frequently use it for "plugins" where I have a directory full of files with subroutines, and AUTOLOAD just runs 'require' to pull it in, but the subroutines in the files look normal, and everything is easy to use/debug.
      Couldn't you be better served by making those files into modules/objects and choosing which one(s) you want at the beginning, making it clearer to your maintainer(s) (which often is you) exactly what's going on?

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        I use the same technique - in my case it is for a database abstraction layer, where each file/subroutine describes a db access method, like this:
        package DBAccess; use strict; use Sybase::CTlib; sub addMaillog { my $self = shift; my %args = @_; my $config = { name => 'addMaillog', param => { token => { type => CS_CHAR_TYPE, opt => 0}, email => { type => CS_CHAR_TYPE, opt => 0}, action => { type => CS_CHAR_TYPE, opt => 0}, }, output => [ { name => 'maillog', cols => [qw(maillogId)], }], server => 'main', database => 'rpc', }; $self->execute($config, \%args); } 1;
        Each file only has this description, and everything else is handled by the rest of the package.

        It makes adding/modifying database requests very easy, though the fact that they are all stored procedure calls simplyfies things as well. There are no doubt other ways to do this, but it works fine for me at the moment.

        Note that this is based on Sybase::CTlib, but it could very well be built using DBI/DBD::Sybase as well.

        Michael

Re: Re: goto and AUTOLOADed methods
by fergal (Chaplain) on Aug 01, 2003 at 15:48 UTC
    I agree, autoloaded accessor are probably a bad idea but that's not what I was doing. Did you read my comment on what I was actually doing with AUTOLOAD?

    Another use I had was an object proxy. Basically you connect to an object server, get an ID from that server, it gets wrapped in an object on the client side which looks like

    package ProxyObject; sub AUTOLOAD { my $self = shift; $method = $AUTOLOAD; $method =~ s/.*:://; return $self->{HomeServer}->call_method($method, $self->{ID}, \@_); }
    the HomeServer object sends the method, the id and the args back to another server which calls the method on the correct object, passing in the args and then passes the result back across the network.

    In use it looked like

    my $server = Server->connect( host => auth.domain.com user => $user, pass => $pass ); my $root = $server->getRoot; # this is a proxied object my $users = $root->getUsers; # another proxied object my $fergal = $users->getUser("fergal"); $fergal->setPasswd("wibble"); $fergal->setShell("/bin/zoidberg"); $fergal->commit;

    Your Perl code neither knows nor cares that some of the objects it's playing with doesn't actually exist on this machine.

      Why wouldn't you use something like SOAP::Lite here? (Please note that I'm a SOAP novice, but it seems like it would do the trick here ...)

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        I looked at SOAP, thinking it might solve all my problems but SOAP seemed to me at the time to be for 1 shot remote calls. You send some data, you get some data back. You don't get an object that you can then call methods on just like any other object that your program uses. The data that comes back is just hashes and arrays etc, no objects.

        Of course you could then wrap up the data that came back in an object and call methods on it, which is basically what I was doing except I wasn't using SOAP to transmit the arguments and results of the function calls. The other difference is that SOAP doesn't have persistent connections so the server keeps having to save and restore the object from a database every time you call a method on it. The system I wrote maintains 1 process for every connection to it. Not ideal in some situations but exactly what I needed for my situation. Possibly more like J2EE, but I coudn't be sure about that.