in reply to Re: Idea on a Base class API
in thread Idea on a Base class API
my @attribute_names = ('attr1', 'attr2', 'attr3'); foreach my $attribute (@attribute_names) { my $value = $self->get($attribute); print "$attribute => $value\n"; }
This is as opposed to how it would have to be using get_foo() or set_foo(). That would look something like:
my @attribute_names = ('attr1', 'attr2', 'attr3'); foreach my $attribute (@attribute_names) { my $function_name = "get_$attribute"; my $value = $self->$function_name; print "$attribute => $value\n"; }
I ask you ... which is clearer? Of course, there's an even clearer way to do that exact same thing:
my @attr_names = ('attr1', 'attr2', 'attr3'); my @values = $self->get(@attr_names); print "$attr_names[$_] => $values[$_]\n" for (0 .. $#attr_names);
Personally, I think that Example 3 is the cleanest of all.
Now, the biggest problem I have with Example 2 (and its cousin, $self->$attribute;) is that you're using a string as a function name. Can you guarantee that this function exists? Maybe, but it's a lot of work, and you restrict your options. For code that will always handle exceptions gracefully, you want to have your function names hard-coded. That way, you will always be executing something.
A nifty benefit, too, is that you're expanding your options of viable code, as you can see from Example 3.
The expected behavior of define_attributes() when called on a class with instances out there already is ... well ... not determined yet. Certain implementations of objects mandate that the attributes will get added immediately, and others mandate that it has to be done by hand. I, personally, would say that if you call define_attributes again, that you will add new attributes to all instances, present and future, and that's just the way it has to be.
A more important problem is what happens when you call define_attributes() on the same attribute. Or, what happens when Foo overrides the allowable types on attrib1 inherited from Bar. These are the decisions that have to be put into the contract, and that's why I'm putting the draft of the contract out there for everyone to read and comment on. :)
Now, to your objection about needing to add extra conditionals when dealing with set() ... that's a good objection, and one that I hadn't really thought of. Three possible answers immediately come to mind:
And, no, I'm not quite sure how that would be implemented. But, that's not the point in this discussion. The idea is to figure out what is desired.FooClass->define_attributes( foo => { Type => 'MULTIPLE(x)', Default => 0 }, );
|
---|