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

Choosing between AUTOLOAD vs Delegation

We are using OOP perl as a programming languge to design this framework, so this algo-like code is in Perl.

We are developing an automation framework in OOP Perl for an end-point device. This end-point device provides a HTTP, Telnet and SSH interface to execute the certain set of commands. For simplicity, we can assume that all commands are supported by all the three connection interfaces, generating the same output for a given command.

A function is written in the respective Connection class to handle a specific command. e.g.

sub getVersion { return $http->sendCommand('version'); }

But the current implementation of calling such function is little but different. Suppose, we would like to call the getVersion function, then it will be called something like this.

$device->getVersion(); //This is called through device object rath +er than connection object.

since this function is not defined in the device class, AUTOLOAD is called. In the Device class, AUTOLOAD is implemented like this

sub AUTOLOAD { my $connection = $device->getConnection(); return $connection->$methodName (..); // when called for getVers +ion, $methodName will become the "getVersion" }

Later, through some other forum, I identified about the class Class::Delegator. If I use Class::Delegator then we need to write the hash for each and every sub which will be deligating. I have 150+ such functions which all will be deligated to a single attribute.

Please help me to identify whether I should stick with AUTOLOAD or should I move to Class::Delegator class.

Replies are listed 'Best First'.
Re: Choosing between AUTOLOAD vs Delegation
by Jenda (Abbot) on Mar 12, 2012 at 15:17 UTC

    I'd stay with AUTOLOAD. Just make sure you document it so that people are not confused when they mistype a method name and get informed that the method is not defined in the Connection class even though they called it on an instance of a Device class.

    You might also try to test whether the $connection->can($methodName) before calling it and maybe even build and eval"" a delegator if the connection does support that method so that the next call to the same method doesn't have to go through AUTOLOAD again.

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

Re: Choosing between AUTOLOAD vs Delegation
by BrowserUk (Patriarch) on Mar 12, 2012 at 15:48 UTC
    Please help me to identify whether I should stick with AUTOLOAD or should I move to Class::Delegator class.

    Three thoughts come to mind reading your post:

    • The word "should" implies some law, rule or at least good reason for, doing something.

      That reason could be because of your organisation rules: how would a bunch of strangers on the internet know those?

      Or the reason could be efficiency or ease of maintenance of the implementation: trading a single simple subroutine for 150+ subroutines doesn't seem to be a good reason.

      Or perhaps you think that what you have is not OO enough: allowing such academic criteria to override your own assessment is a very bad choice.

    • It strikes me that whilst inheritance is way overused, this is actually tailor made for it.

    • If your current mechanism works, and doesn't cause you problems, stay with it.

      I might make one change though. Assuming that only one type of connection will be used in any given application:

      sub AUTOLOAD { my $connection = $device->getConnection(); { no strict 'refs'; *{ __PACKAGE__ . '::' . $methodname } = $connect->can( $method +name ); } return $connection->$methodName (..); // when called for getVersio +n, $methodName will become the "getVersion" }

      Now, the AUTOLOAD process will only be used the first time a method is called, which could effect a nice performance boost if many calls are made to some methods.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      I agree with your:

      *{ __PACKAGE__ . '::' . $methodname } = $connect->can( $methodname );

      ... in principle, but in practice it has a subtle bug. (OK, there's the $connect versus $connection typo too, but we'll ignore that as strict mode should make it obvious.)

      The first time the autoloaded method is called, the connection object is passed to the method as its invocant. Subsequent calls will get the device as the invocant.

      What should be used is something more like:

      sub AUTOLOAD { no strict 'refs'; *{__PACKAGE__.'::'.$methodname} = sub { (shift)->getConnection->$methodname(@_) }; return (shift)->getConnection->$methodname(@_); }

      Also it's worth noting that whenever you write an AUTOLOAD method, it's worth considering writing a can method, because the default method inherited from UNIVERSAL::can ignores autoloaded methods.

      Class::AutoloadCAN explains the issues around AUTOLOAD and can and offers a solution. Personally I've found Class::AutoloadCAN a little buggy myself and ended up re-implementing it on a module-by-module basis (e.g. these __autoload, can and AUTOLOAD methods).

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Choosing between AUTOLOAD vs Delegation
by JavaFan (Canon) on Mar 12, 2012 at 15:15 UTC
    Later, through some other forum, I identified about the class Class::Delegator. If I use Class::Delegator then we need to write the hash for each and every sub which will be deligating. I have 150+ such functions which all will be deligated to a single attribute.

    Please help me to identify whether I should stick with AUTOLOAD or should I move to Class::Delegator class.

    If your AUTOLOAD solution is working for you, and the Class:Delegator seems like too much work for you, I don't think it makes any sense *now* to change.

    If later in the project it turns out you may have to reevaluate this position, you can always do the work then.

Re: Choosing between AUTOLOAD vs Delegation
by Anonymous Monk on Mar 12, 2012 at 14:53 UTC

    I have 150+ such functions which all will be deligated to a single attribute.

    To try to delegate that many functions smells like a design flaw

Re: Choosing between AUTOLOAD vs Delegation
by locked_user sundialsvc4 (Abbot) on Mar 13, 2012 at 13:09 UTC

    I have recently been using RPC::Any and its very generalized mechanism for locating and invoking service modules (and yet, for doing so selectively... you can’t just make strings up i.e. to probe or attack the system) might be useful as a practical example for study.

    Am I suggesting that it is exactly the same?   Clearly, no.   (It isn’t even closely related to the expressed goal.)   But it does implement an important part:   it does implement the easy ability to delegate even to “hundreds of” service routines which don’t have to be separately listed, and to “automagically” demand-load these modules without resorting to sugar.   And, it’s right now in actual high-volume production use.   So, it might be a good source of ideas and implementations that could apply.