* Hans Dieter Pearcey <[email protected]> [2010-09-30T14:35:13]
> We don't like the fact that lazy_build autogenerates public clear_$attr and
> has_$attr methods for you. OK, I can get behind that; those often don't
> belong as part of the "public" API, and yes, people will consider them public
> if they don't have a leading underscore, even if they aren't documented.
I am really not excited about doing anything to remove lazy_build. I'd rather
see something better introduced so that lazy_build is a lousy option. Let's
talk about other options, and then the question of deprecating lazy_build or
not is less interesting to me...
We discussed this on #moose-dev for a while today, and one of the suggestions
that seemed to get some general favor was this (mine):
Allow anything that takes a method name to do a very, very simple expansion
on the name, replacing some token with the attribute name.
For the sake of discussion, we used $. I think that's also a tolerable thing
to actually use, but I am not too worried about it.
So, for example, these are equivalent:
has foo => (builder => '_build_$');
has foo => (builder => '_build_foo');
This is a relevant change for the topic at hand because now I can write this:
sub lazy_build {
return (
lazy => 1,
builder => '_build_$',
clearer => 'clear_$',
predicate => 'has_$',
);
}
has foo => (lazy_build, ...);
(Read on, if you think that the non-pair item sucks, before complaining!)
Another unrelated benefit is that we can get rid of the need for 'is' because
we can:
sub rw {
return (accessor => '$');
}
Then, while you could always give a full name for attributes, you could also
have these "policy" routines that return a set of methods to add. There's no
need to make each one a trait, they work very well as pairs.
...but, as I noted above, the routine call breaks the pair-looking structure
in:
has foo => (
lazy_build(),
isa => 'Meta',
);
There were two suggestions, the first Sartak's, the second mine:
# Sartak said, what about:
sub rw_lazy_build {
return ('rw', builder => '_build_$', clearer => 'clear_$');
}
has foo => (is => rw_lazy_build);
I suggested:
sub lazy_build {
return { builder => '_build_$', clearer => 'clear_$' }
}
has foo => (
policy => lazy_build,
);
"policy" (or, as I suggested at the time, "attr") would basically flatten the
hashref given and use it as more args. If desirable, it could detect
conflicts or allow overrides. "Your policy said clearer=>clear_$ but you also
said clearer=>undef, so no clearer."
Finally, I think the (builder => 1) is a good idea. I would implement it by
saying that there is a attribute mapping method types to default strings, so
the default string for a builder can be '_build_$' and for accessor '$' and so
on.
has foo => (
accessor => 1,
builder => 1,
clearer => 'reset_$',
...
);
Policy traits can then just change the default strings, which would be quite
convenient.
I think there's a lot of power to be gained from this pretty simple change,
almost no matter what parts of the suggestions we choose.
P.S., we may want a second indicator for "_ iff attr name begins with _" for:
clearer => '?clear_$'
...but any further special markers would be an abomination.
--
rjbs