On Mon, May 31, 2010 at 4:57 PM, Kate Yoak <[email protected]> wrote:

>
> You are basically right, philosophically, anyway.  I asked myself the same
> question when I was writing, "Why was it, again, I didn't just want to apply
> the Role?"  Now I remember.  :-)

Yeah it's taken me several years to get to understanding this point
where I feel I can even begin to express it sensibly, and several more
months thinking about how to express it sensibly. I'm still not happy
with the way I put it, but "meh" you got the point :)

> Setting aside the fact that delegation doesn't work the way i'd like because
> of a bug - this is much more interesting to look at anyway, here it is.
> Let's say, you have a Cloud that is implemented with 'Rain'. Your various
> objects may want to aggregate the cloud and delegate the behavior instead of
> inheriting (via a role) because the Cloud objects will contain the necessary
> data that it important to share across the system.
> Thus, saying sky->pour, roof->pour, god->pour will use up the raindrops in
> the Cloud that's actually doing the raining.
> Ok, my metaphor is running out of steam, but you get the idea, particularly
> if Cloud opens files and has state.

Yes I fully agree with this. The important part is the fact that the
Cloud is a single component that is re-used and maintains it's own
state. So using your example we have a Sky model that delegates the
rain() method to a RainCloud[HASH0x...] instance based on the fact it
does the RainSource Role.

class Sky { has cloud => ( ... does => [RainSource], handles =>
'RainSource' ... }

This allows us to later say add a metaclass trait to our Cloud
instances so we track the Cloud instances and get some feedback on how
they perform in the model:

class Cloud { use MyApp::Trait::InstanceTracker; }

Cloud->meta->map_on_instances(sub { my $cloud = shift; report $cloud->state })

> In implementing this, you will often need access to the attributes along
> with the methods. For instance, after pouring the rain, you might check
> remaining() or weight() or tail the rain log using file location. I can see
> a lot of cases when , in English, we delegate attributes, if you will.  Like
> how much gas does the Car have? (Attr delegation to Tank).

Exactly the *state* is part of the Tank while the behavior for
reporting that state is delegated up to the Car.

Human though (and English or Perl as expressions of it) is full of
whole/part category mappings, it's one of the ways we function at a
fundamental level. One of the things that makes our thinking powerful
is the ability to use whole/part mappings to "dig deeper" and build
more detailed models as we need. There are some great books on the
cognitive science underpinnings of how we perform categorizations and
build models of the world around us. Women, Fire, and Dangerous Things
by George Lakoff is an excellent example even if it does tend to put
me to sleep.

> How fast is the
> computer (delegation to CPU), how much RAM does it have? and so on. I think,
> I have convinced myself in the process of writing that attributes are no
> different when it comes to delegation.

Encapsulation demands that you should be able to replace behavior with
state (your earlier caching example) and state with behavior without
the outside world noticing. So at that level yes; attributes and their
associated behaviors (accessors, readers, writers, clearers,
predicates, etc.) are interchangeable as far as the outside world
cares.

> The way I solved my problem is via an AUTOLOAD function.  It passes
> everything that the object supports.  It should be made even cleaner if I
> first check if the Role implements that method. Is this a good workaround
> for the bug, do you think?

AUTOLOAD in a system that provides Class->meta->add_method() always
makes me queasy. However if you have it working and well tested,
whatever gets the job done.

-Chris

Reply via email to