Here is the problematic points of your code: 1. There is currently a bug (or bugs) about wrapped methods – https://github.com/rakudo/rakudo/issues/2178 get_value() is unlikely to be wrapped. But potential issues are possible as it seems that the bug is not only related to method inheritance.
2. set_value() does not what you expect it to do. Actually, you're replacing attribute's container. Congratulations, now you have untyped attribute! ;) You could workaround the problem by cloning $.auto_viv_container but I foreseen side-effects with array and hash attributes. 3. This approach doesn't let clear/trigger/predicate to exists. While the first two are possible (just don't restore the wrapped get_value and continue to intercept fetch operations), predicate won't work properly because it must signal about any store done, including Nil. In other words, there must be a flag of some kind signaling that attribute was written into. 4. Build must not be called if value was set. And this is where it call comes to a really surprising point: set_value() is not used to set attribute. As a matter of fact, it just never used – try grepping the source. There is one declaraion in moar's CORE.setting and one in Attribute.pm6. So far, what you've done is similar to my first steps on this road... ;) > 6 вер. 2018 р. о 04:29 Simon Proctor <simon.proc...@gmail.com> написав(ла): > > Done a bit of noodling about this morning and I got this. And it works.... > sort of. > > .perl calls the get_value method but the accessor and private value reads > don't. (I'm guessing this is what you came up against Vadim?) > > Still the self deleting wrapper is a fun trick. Best I do some work now > though. > > use v6.c; > > role LazyAttr { > has $.get-wrapper is rw; > } > > multi sub trait_mod:<is> ( Attribute $a, :@lazy [ &builder ] ) { > $a does LazyAttr; > > $a.set_build( > -> |c { > $a.get-wrapper = $a.^find_method('get_value').wrap( > -> $self, $instance { > my $val = &builder( $instance ); > $a.set_value( $instance, $val ); > $a.get-wrapper.restore; > $val; > } > ); > Any; > } > ); > } > > class Test { > > sub build-a( $self ) { note "Build A Called"; sleep 1; 5 } > sub build-b( $self ) { note "Build B Called"; sleep 2; 10 } > > has $.a is lazy[&build-a]; > has $.b is lazy[&build-b]; > } > > my $t = Test.new(); > > say $t.perl; > > On Wed, 5 Sep 2018 at 23:45 Vadim Belman <vr...@lflat.org > <mailto:vr...@lflat.org>> wrote: > Looking forward to see what you come up with. I do mix in a role into both > Attribute and ClassHOW. But delving into the core didn't help to find a > better approach than the one I finally took. Two subtle aspects are to be > kept in mind: support for roles; and knowing the object attribute is > belonging to. > > > So I have a thought for how to do lazy attributes without Proxy objects. It > > is late so I'll try and poke about at it tomorrow but I think we can Mixin > > a role to the Attribute using a trait. > > > > The role will track if the attribute was set to a value at build and if not > > call a block it's given when first read from. This gets round the issue of > > if we want to set it to Any. > > > > I *think* this will work. The stuff I've been doing with Trait::Env would > > point that way. > > > > Best regards, > Vadim Belman > > -- > Simon Proctor > Cognoscite aliquid novum cotidie Best regards, Vadim Belman