* 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

Reply via email to