> From: Luke Palmer [mailto:[EMAIL PROTECTED]
>
> Austin Hastings writes:
> > Suppose that I have, for example:
> >
> > class Session {
> > has @:messages;
> >
> > method clear_messages() {...}
> > method add_message($msg) {...}
> > method have_messages() {...}
> > method get_messages() returns Array {... font color="black" ...}
> > }
> >
> > And suppose I add to it:
> >
> > class Session {
> > has @:messages;
> >
> > method clear_messages() {...}
> > method add_message($msg) {...}
> > method have_messages() {...}
> > method get_messages() returns Array {... font color="black" ...}
> >
> > has @:errors;
> >
> > method clear_errors() {...}
> > method add_error($msg) {...}
> > method have_errors() {...}
> > method get_errors() returns Array {... font color="red" ...}
> > }
> >
> > So I realize that not only is the whole list-of-messages thing
> > a packageable behavior (read: Role or Class) but that this particular
> > behavior recurs within my class.
>
> So what you want is a role whose names are private to the role, not the
> aggreagating class. Well, I believe private (i.e. $:foo) variables do
> that anyway, so you can just abstract your messages out into a role and
> it will work fine. But if you read on, I'll offer some unsolicited
> design advice.
Hmm. No. I want a role whose methods are available in the composing class, as shown.
Variables (members) don't have roles: Roles (may) have variables.
Saying "class Session does MessageList" means that MessageList may impose member
variables on Session, and will provide methods to Session. Roles are composition, not
aggregation.
> > One solution is to compose member objects that implement this behavior:
> >
> > if ($my_object.messages.have_messages) {...}
> >
> > But that sucks.
>
> Why? From a design perspective, that's the correct way to do it. What
> if you have a routine that operates on message lists -- pruning them or
> somesuch. If you do it by renaming the methods, you break any kind of
> future-proof code reuse that abstracting gets you in the first place.
You've got it backwards: saying $my_object.messages.have_messages is exposing the fact
that the have_messages functionality is implemented via a member data item, instead of
querying the $my_object directly.
> But I'll agree that:
>
> if $my_object.messages.have_messages {...}
>
> Kinda sucks. But you'll find that things that suck in this particular
> way can be solved by tersifying your method names.
>
> class MessageList {
> method ready() {...}
> method add($msg) {...}
> method clear() {...}
> method get() {...}
> }
>
> There's no reason to repeat _message on the end of each method when
> you're already in a class about messages. And then you have:
>
> if $my_object.messages.ready {
> say for $object.messages.get;
> }
>
> Which is quite more tolerable, IMO.
>
> But this isn't an OO design list, it's a language design list.
And "how to make the names more readable" isn't "how to parameterize member/method
names".
>
> If it turns out that role private variables leak, I might suggest making
> a MessageList class as above, then making a role that knows how to turn
> a MessageList into a set of methods. Then you'd pass the role the
> MessageList object which you instantiate yourself, and it would generate
> the methods for you. That's kind of a kludge, but you're using roles
> for something they're not really intended for, so that's what you get.
> Keep in mind that there are plenty of other ways to do what you want;
> this is Perl, after all.
Hmm. Why is this not what roles are intended for? I have identified a packageable,
reusable behavior that I want to insert into a class using some mechanism other than
inheritance. I could have sworn that was the whole point of roles.
In this particular case, however, I've gone one step beyond and identified a "generic"
behavior, that I'd like to implement multiple times with slightly different names.
=Austin