3

My Moo based class has both lazy & non-lazy attributes which have both default and coerce subs. If I don't initialize the attributes I'm finding that both default and coerce subs are called for the normal attribute, but only default is called for the lazy attribute. That seems inconsistent. Here's sample code:

package Foo;
use Moo;

has nrml => ( is => 'ro',
              default => sub { print "nrml default\n" },
              coerce  => sub { print "nrml coerce\n" } 
            );

has lazy => ( is => 'ro',
              lazy => 1,
              default => sub { print "lazy default\n" },
              coerce  => sub { print "lazy coerce\n" }
            );



my $q = Foo->new( );

$q->lazy;

The output is:

nrml default
nrml coerce
lazy default

I only expect coerce to run if I provide a value in the constructor. More importantly I expect the same sequence of execution (either default or default and coerce) from both lazy and normal attributes.

So, are my expectations off, is this a bug, or what? Thanks!

tobyink
  • 13,478
  • 1
  • 23
  • 35
Diab Jerius
  • 2,310
  • 13
  • 18
  • I suggest you use a 'builder' rather than default for anything more trivial from a simple scalar for your default values. this is not an answer to your question but some suggestion. – snoofkin Mar 17 '12 at 01:47
  • Isn't `builder` designed for situations where child classes need access to the parent's attribute creation method so that they can modify it? For classes which will not be subclassed `default` seems more to the point. – Diab Jerius Mar 17 '12 at 02:08
  • For completeness I replaced default with a builder; same results as before. – Diab Jerius Mar 17 '12 at 02:46
  • With Moo 0.9.7 i got in output only default lines: `nrml default lazy default ` – w.k Mar 18 '12 at 06:22
  • I should have mentioned the version I'm using: 0.9.13. – Diab Jerius Mar 18 '12 at 14:06

2 Answers2

6

Current status: fix shipped in 009014

One of those two is a bug.

In fact, thinking about it, one could argue either way about whether coercions -should- be fired on defaults but since Moose does do so, and since coercions are structural (unlike type checks, which are often used for assertion-like things and should always pass except in the presence of a bug), I think it falls that way.

... in fact, the problem is that Method::Generate::Accessor when it fires _use_default always wraps it in _generate_simple_set, when it's _generate_set that provides the isa+coerce+trigger wrapping - and I'm fairly sure that Moose fires all three when it's applying a default, so we need to too.

It's not an entirely trivial fix to make though, because I didn't parameterise _generate_set to take a value indicating how to generate the value to set. I'll try and sort it out tomorrow since I'm planning to cut a release then.

If you want support for Moo from the developers, please contact bugs-Moo@rt.cpan.org or join #web-simple on irc.perl.org - it's sheer luck that somebody on the IRC channel saw this question and asked about it :)

  • Thanks for the response. I wanted to make sure I wasn't doing something stupid before filing a bug report. Happens sometimes. – Diab Jerius Mar 17 '12 at 23:01
  • Totally, and I appreciate trying to keep the bug queue clean! But equally I'm quite happy with you asking on IRC if you're doing something stupid, or even coming onto IRC and waving a stack overflow link at us :) – mst - Matt S Trout Mar 24 '12 at 18:07
3

That would qualify as a bug to me. Either the value from default is expected to be of the right type, or it's not. Having and enforcing the expectation only half of the time makes no sense.

ikegami
  • 367,544
  • 15
  • 269
  • 518