A. Pagaltzis writes: > * Smylers <[EMAIL PROTECTED]> [2003-11-02 18:05]: > > > However, even now I know the name for the technique I don't > > think it'd be appropriate to call the module > > Class::InsideOutAttributes (or similar), because that is > > describing the module's implementation rather than the > > situation in which it is useful. > > How is "FakeAttributes" any less dependent on implementation?
Well it isn't a great name -- that's one of the reasons for posting here, in the hope of somebody coming up with a better one! > The attributes aren't fake, they're actual subclass attributes, only > called "Fake" because they don't live in the $self hashref. Exactly. They're 'fake' in that they aren't considered part of the object by Perl (and won't be freed by Perl automatically on destruction). > An actually implementation agnostic name would probably be something > like ::SafeInheritance. (Which it isn't completely though, but see > below.) Possibly. But safety isn't really the point -- Wx::StaticBoxSizer can safely be inherited from, it's just that there isn't anywhere inside it to store some instance data. So the class enables instance data to be attached to an object ('faked' as part of it), rather than adding any safety. > > Class::FakeAttributes helps in a different situation, where a > > class author is subclassing something that is based on, for > > example, a scalar ref but he/she wants to add instance data in > > the subclass. > > Yes, Abigail invented inside out objects for two reasons - one of them > being to be able for a class to be completely superclass > implementation agnostic. Including choice of superclass $self data > type. That's a good reason; that would be a reason for all Perl objects doing all of their attributes like that (well, except when subclasses want to access their parents data ...). > > The methods in this class are intended to help the subclass author > > access the attributes inside the class definition, not to provide > > public methods for use by the people creating objects of that class. > > But that loses the other advantage of inside out objects: compile time > stricture checking. Whether it 'loses' them depends on where you start from: * If you start with wanting to implement an inside-out object (or even with an inside-out object, or with Abigail's unreleased Class::MethodMakerInsideOut) then obviously using my module instead means you've lost an advantage of inside-out objects (but that wasn't its purpose). * But if, instead, you start with Wx::StaticBoxSizer and want to subclass and add some attributes then my module helps to do that -- you can't have lost anything that you didn't have in the first place. > If you write > > $attribtue{$self} > > (note the typo for $attribute), Perl will complain. If you write > > $self->get_attribute('attribtue') > > that's a runtime error at most. In your module, it isn't even that > much, because you don't ask the classes' author to declare the > attribute names so you can't check them. That's intended. I'll make this as clear as I can: My module is not intended to be a general implementation for people who want inside-out objects! Anybody wanting such a module will be disappointed by trying to use my module! My module is intended to be used by somebody who wanted to write: $self->{attribute} but can't, because of the implementation of the parent class. That's all my module aims for, and nothing more. And of course anybody who normally does $self->{attribtue} doesn't get any compile-time checking either. > In general I find the interface rather ill thought out; of > course, if it did the job for you, hey presto. > > But I'd prefer to do > > for(@{$self->get_attr('foo')}){ ... } # A > > rather than > > for($self->attribute_list('foo')){ ... } # B Believe it or not, so would I! Because, in a 'normal' class I'd just write: foreach (@{$self->{foo}}) { ... } # C so merely using $self->get_attribute('foo') in place of $self->{foo} would seem like the most natural alternative. And that's what I did first. The only flaw with that approach is that it doesn't work! If the 'foo' attribute hasn't been set to anything, then you want an empty list to iterate over. With version C, that's what you get. But with version A get_attribute() returns undef, which yields an error when trying to dereference it. So that's why I came up with version B. (There's equivalent reasoning behind the existence of push_attribute().) I don't entirely like the fact that these different methods exist. An alternative would be to have the constructor initialize all array refs that might ever exist in an object to []. That way version A will always work, because there's never an attempt to dereference undef. Now you've brought that up, it makes sense to add it to the module docs: if you make sure you always initialize your array attributes then get_attribute() and set_attribute() are all you need; but if you don't then make sure you use push_attribute() and attribute_list(). That way it's the class-user's choice, depending on whether he/she likes initializing things or not. > > But if the consensus of this list is that I should remove > > Class::FakeAttributes from Cpan then I shall do so. > > So far it's one man's opinion; that hardly counts as consensus. Well if nobody else joins in this thread then it looks like the vote is tied, 1 each way (assuming that I count my own opinion; perhaps I shouldn't) ... which is a little awkward for being decisive! > Actually I just noticed it's not even inside out objects. If two > classes in a hierarchy where one is an ancestor of the other both use > ::FakeAttributes, they can *still* trample over each other's > ::attributes, so you still need to know all your ancestors' > ::attributes' names (including private attributes). Yes. Because that's always the case with 'ordinary', hash-ref-based objects too. This module is simply trying to provide a way of faking having a hash-ref-based object when an object is actually based on something else. It does not attempt to provide any features whatsoever that you would not have with a hash-ref-based object! I think that the main problem here is that I've written a module to do X that happens to look a little like it might do Y, but it isn't any good at doing Y and you don't like the fact that it does Y so badly? It isn't that I don't consider Y to be a valid problem to solve, nor even that I'm against the existence of a module that solves Y. It's just that it isn't this module. Sorry that go so long. Does any of that make any sense? Smylers