in reply to Private methods
Whether or not this code will cause problems depends upon how annoying the programmer finds the constructor's side effect of writing information to STDERR. Personally, I would not want that. However, I want to take a moment to go over your code because I see a few things that I might do differently. This isn't an answer to your question, per se, but more of a meditation regarding general coding style that might provoke interesting discussion.
01: my $_init_ = sub { 02: my $self = shift; 03: print STDERR ref($self) . "::_init_ called\n"; 04: }; 05: 06: sub new { 07: my $type = shift; 08: my $class = ref($type) || $type; 09: my $self = { 10: attribute1 => undef, 11: attribute2 => undef, 12: }; 13: bless $self,$class; 14: $self->$_init_(); 15: return $self; 16: }
I don't have a problem with you wanting to use a private method, but I disagree with how you're using it (I think the printing to STDERR was merely to show us how this works and not a programming technique you actually use, so I'll skip that). Instead, I'm more concerned with how you are using $_init_. Generally, I would see something like the above written as:
sub new { my $class = shift; my $self = bless {}, $class; $self->_init; } sub _init { # instance initialization }
If you have specific initialization for the instance of an object, it goes in _init and class initialization would be in new. (Many programmers put all of the initialization in _init() so that new() creates an object and _init() initializes it.) With that, subclasses can inherit new, get the appropriate class information and override _init to provide instance information appropriate for their class. However, this means overriding a private method!
This seems to be a highly contested issue with Perl OO programmers. Most feel that private methods should remain private and only the public interface should be exposed (which I now tend to agree with). Others seem to feel that you can override anything you want. If you need to get something done, sometimes the best way is to break the rules.
In the case of your code, you have an _init method that isn't initializing anything and can't be overridden. The latter may not be bad, the former however, is not good. It's not behaving the way I would expect it to and thus you haven't gained anything that I can see.
One way to deal with this might be to create two public methods. One is the constructor that sets class data. The other is initialize(), which sets instance data. If the class needs to be subclassed, the subclass only needs to override initialize(). This makes object construction a bit more cumbersome, though.
my $foo = Foo->new()->initialize(\%data);That's not to say that private methods are useless, but I would want to see a more pertinent example before I could comment on how you are using it.
I'm also wondering about your lines 07 and 08:
07: my $type = shift; 08: my $class = ref($type) || $type;
I'm wondering why you have the ref($type) || $type in your code? That statement suggests that you might call new as a class method (Foo->new) and your might call it as an instance method ($foo->new). As a class method I understand, but as an instance method, it behaves as a class method, so why not call it as a class method? Calling it as an instance method can confuse programmers:
$employee{Sally} = Employee->new; $employee{Bob} = $employee{Sally}->new;
Without looking at the Employee package, I have no way of knowing what that's doing. Is Sally a really good worker so I decided that Bob is a clone of Sally? If I want to do something like that, I may as well just create a clone method to make the example more clear and to doom Bob to a life of gender confusion (not to mention the fact that the Catholic Church also objects to this practice):
$employee{Sally} = Employee->new; $employee{Bob} = $employee{Sally}->clone;
Unless you actually have code that uses the ref $proto || $proto construct, I would leave it out. But when might you need it? When a class method can also be appropriately called as an instance method. For example, I have a program where each object has a mapping of accessor/mutator names to the column names in the database. Thus, I can change the column name, update it in the object's map and I don't have to change the method names. But what happens if an object in a different class needs to get the column name? (for example, when needing dynamically built SQL.) I use the following method:
sub accessor_to_column { my ($proto,$column) = @_; my $class = ref $proto || $proto; # note the lexical variable to store class data my $found_column = 'id' eq $column ? $CLASS_DATA{$class}{id} : $CLASS_DATA{$class}{accessor_to_column}{$column}; unless ($found_column) { croak "No column found for ($column)"; } return $found_column; }
With this method, I might need to call it on a class, but I might also be calling it on an object instance. In both cases, the behavior must be the same, so the ref $proto || $proto trick is appropriate.
Thanks for letting me ramble and I hope I didn't take your code too seriously as an example of what you might actually be inclined to implement.
Cheers,
Ovid
New address of my CGI Course.
Silence is Evil (feel free to copy and distribute widely - note copyright text)
|
---|
Replies are listed 'Best First'. | |
---|---|
Re^2: Private methods
by adrianh (Chancellor) on Mar 09, 2003 at 23:17 UTC | |
by Ovid (Cardinal) on Mar 10, 2003 at 01:08 UTC | |
by adrianh (Chancellor) on Mar 10, 2003 at 09:27 UTC | |
by Aristotle (Chancellor) on Mar 11, 2003 at 02:57 UTC | |
Re: Re: Private methods
by crouchingpenguin (Priest) on Mar 09, 2003 at 19:08 UTC | |
Re: Re: Private methods
by hardburn (Abbot) on Mar 10, 2003 at 15:25 UTC |