Daniel,
On Jul 26, 2009, at 5:06 AM, Daniel Pittman wrote:
G'day.
In implementing a Moose::Role I have run into a question that I
can't find an
easy or obvious answer to in the documentation.
So, in my role I have several methods that need to perform some non-
trivial
operations that are identical, but which are also strictly internal:
they are
not part of the API, because they are not really useful outside the
code,
especially if I change the implementation at all.[1]
So, at the moment I do this:
package Example;
my $find_stage = sub { my ($self, $arg) = @_; ...; };
sub dance {
my ($self, $where) = @_;
my $stage = $find_stage->($self, $where);
...;
}
sub sing {
my ($self, $where) = @_;
my $stage = $find_stage->($self, $where);
...;
}
That ensures that I don't go leaking the 'find_stage' method as part
of the
API, or conflicting with other roles or the base class, or
whatever. The
"Stage", for what it is worth, is an implementation detail; it isn't
useful
without the context of the role.
So, is there a better way to implement a private method — one that
isn't
available outside the context of the role, and isn't exported?
No, I think this way is the best if you truly want privacy.
Hmmm. In writing this all down I had to think about it, and it
occurs to me
that I might be facing this problem because of a higher level design
decision.
At the moment I create one attribute each time a "stage" is created
on the
class; the methods in the role then look those up using the MOP by
name in
order to obtain the internal implementation.
This sounds wrong unless you are creating an anon-class for each
instance. Otherwise your class will just keep getting attributes added
to it that all instances share (even if they have different "stage"s).
I could, I guess, replace that with a single attribute containing a
hash,
mapping names to "stage" instances. The sing and dance methods
would then
need to do a hash lookup in a know attribute, so the entire helper
could be
eliminated...
This sounds a lot saner to me.
In this case the "stage" is a semantic feature similar enough to an
attribute,
so an object could conceivably have quite a few of them, but the
average would
probably be somewhere around half a dozen or so.
If you actually "program" with these stages, then you might consider
moving them up to the meta-level. There is a great paper in the book
"Advances in object-oriented metalevel architectures and reflection"
called "Using the CLOS metaobject protocol to Implement a Frame
Language" that describes adding meta-level "things" to CLOS to
implement a sort of embedded language. Here is a link to the google
book version - http://books.google.com/books?id=pvoefFn_lToC&pg=PA129&lpg=PA129&dq=Using+the+CLOS+metaobject+protocol+to+Implement+a+Frame+Language&source=bl&ots=Veq-Gd7Sj5&sig=ZsgYGcR3cuyxWWIr4U29e-hyTX0&hl=en&ei=oHVsSvbTMsWFtgfP4oibAQ&sa=X&oi=book_result&ct=result&resnum=1
It is a pretty good read even if it is not what you are looking for.
- Stevan