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

Reply via email to