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.
Re: AUTOLOAD - the good, the bad, and the ugly
by chromatic (Archbishop) on Oct 14, 2004 at 18:31 UTC
|
| [reply] |
|
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 ????
| [reply] |
|
| [reply] |
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.
| [reply] |
|
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.
| [reply] |
|
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.
| [reply] |
|
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
| [reply] [d/l] [select] |
|
|
|
| [reply] |
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.
| [reply] |
|
# 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');
| [reply] [d/l] |
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... | [reply] |
Re: AUTOLOAD - the good, the bad, and the ugly
by raptnor2 (Beadle) on Oct 15, 2004 at 02:56 UTC
|
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)
janitored by ybiC: Replace frowned-upon <pre> tags with Monastery-standard <code> tags | [reply] [d/l] |
|
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.
| [reply] [d/l] [select] |
|
| [reply] [d/l] |
|
|