Setting delegated attributes in constructors

--001a11449d38603fed0565154dd1
Content-Type: text/plain; charset="UTF-8"

I'd like to set delegated attributes in my object constructors (e.g. as
below)  but this doesn't seem to work. Am I missing something?

Merlyn


#!/usr/bin/perl

package SubClass;

use Moose;

has thing => ( is => 'rw', isa => 'Int' );

before thing => sub {
    shift;
    print "subthing: ", @_ ? 'set to ' . (shift // '<undef>') : '(read)',
"\n";
    return;
};


package Class;

use Moose;

has sub_object => ( is => 'rw', isa => 'SubClass', handles => ['thing'],
builder => '_build_sub_object' );
#has sub_object => ( is => 'rw', isa => 'SubClass', handles => ['thing'],
default => sub { _build_sub_object(); } );

sub _build_sub_object {
    my $self = shift;

    print "_build_sub_object\n";
    return SubClass->new;
}


package main;

use strict;
use warnings;

print "Start\n";
my $object = Class->new(thing => 1);
print "Built\n";

print "Thing 1 = ", ($object->thing // '<undef>'), "\n";

$object->thing(2);

print "Thing 2 = ", ($object->thing // '<undef>'), "\n";

-- 

-- 
Merlyn

--001a11449d38603fed0565154dd1
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I&#39;d like to set delegated attributes in my object cons=
tructors=C2=A0(e.g. as below)=C2=A0=C2=A0but this doesn&#39;t seem to work.=
 Am I missing something?<div><br></div><div>Merlyn</div><div><br></div><div=
><br></div><div><div>#!/usr/bin/perl</div><div><br></div><div>package SubCl=
ass;</div><div><br></div><div>use Moose;</div><div><br></div><div>has thing=
 =3D&gt; ( is =3D&gt; &#39;rw&#39;, isa =3D&gt; &#39;Int&#39; );</div><div>=
<br></div><div>before thing =3D&gt; sub {</div><div>=C2=A0 =C2=A0 shift;</d=
iv><div>=C2=A0 =C2=A0 print &quot;subthing: &quot;, @_ ? &#39;set to &#39; =
.. (shift // &#39;&lt;undef&gt;&#39;) : &#39;(read)&#39;, &quot;\n&quot;;</d=
iv><div>=C2=A0 =C2=A0 return;</div><div>};</div><div><br></div><div><br></d=
iv><div>package Class;</div><div><br></div><div>use Moose;</div><div><br></=
div><div>has sub_object =3D&gt; ( is =3D&gt; &#39;rw&#39;, isa =3D&gt; &#39=
;SubClass&#39;, handles =3D&gt; [&#39;thing&#39;], builder =3D&gt; &#39;_bu=
ild_sub_object&#39; );</div><div>#has sub_object =3D&gt; ( is =3D&gt; &#39;=
rw&#39;, isa =3D&gt; &#39;SubClass&#39;, handles =3D&gt; [&#39;thing&#39;],=
 default =3D&gt; sub { _build_sub_object(); } );</div><div><br></div><div>s=
ub _build_sub_object {</div><div>=C2=A0 =C2=A0 my $self =3D shift;</div><di=
v><br></div><div>=C2=A0 =C2=A0 print &quot;_build_sub_object\n&quot;;</div>=
<div>=C2=A0 =C2=A0 return SubClass-&gt;new;</div><div>}</div><div><br></div=
><div><br></div><div>package main;</div><div><br></div><div>use strict;</di=
v><div>use warnings;</div><div><br></div><div>print &quot;Start\n&quot;;</d=
iv><div>my $object =3D Class-&gt;new(thing =3D&gt; 1);</div><div>print &quo=
t;Built\n&quot;;</div><div><br></div><div>print &quot;Thing 1 =3D &quot;, (=
$object-&gt;thing // &#39;&lt;undef&gt;&#39;), &quot;\n&quot;;</div><div><b=
r></div><div>$object-&gt;thing(2);</div><div><br></div><div>print &quot;Thi=
ng 2 =3D &quot;, ($object-&gt;thing // &#39;&lt;undef&gt;&#39;), &quot;\n&q=
uot;;</div><div><br></div></div></div>-- <br><div dir=3D"ltr" class=3D"gmai=
l_signature" data-smartmail=3D"gmail_signature"><div dir=3D"ltr"><p dir=3D"=
ltr">-- <br>
Merlyn<br></p>
</div></div>

--001a11449d38603fed0565154dd1--
0
merlyn
2/13/2018 10:17:19 AM
perl.moose 736 articles. 0 followers. Follow

4 Replies
34 Views

Similar Articles

[PageSpeed] 3

Delegated methods are typically used as a convenience technique to
class composition to avoid writing your own wrapper methods that call
the underlying methods the contained object has. It really wasn't
intended to subvert inheritance like you're trying to do.

HTH,
Nick




On Tue, 13 Feb 2018 10:17:19 +0000
Merlyn Kline <merlyn@binary.co.uk> wrote:

> I'd like to set delegated attributes in my object constructors (e.g.
> as below)  but this doesn't seem to work. Am I missing something?
> 
> Merlyn
> 
> 
> #!/usr/bin/perl
> 
> package SubClass;
> 
> use Moose;
> 
> has thing => ( is => 'rw', isa => 'Int' );
> 
> before thing => sub {
>     shift;
>     print "subthing: ", @_ ? 'set to ' . (shift // '<undef>') :
> '(read)', "\n";
>     return;
> };
> 
> 
> package Class;
> 
> use Moose;
> 
> has sub_object => ( is => 'rw', isa => 'SubClass', handles =>
> ['thing'], builder => '_build_sub_object' );
> #has sub_object => ( is => 'rw', isa => 'SubClass', handles =>
> ['thing'], default => sub { _build_sub_object(); } );
> 
> sub _build_sub_object {
>     my $self = shift;
> 
>     print "_build_sub_object\n";
>     return SubClass->new;
> }
> 
> 
> package main;
> 
> use strict;
> use warnings;
> 
> print "Start\n";
> my $object = Class->new(thing => 1);
> print "Built\n";
> 
> print "Thing 1 = ", ($object->thing // '<undef>'), "\n";
> 
> $object->thing(2);
> 
> print "Thing 2 = ", ($object->thing // '<undef>'), "\n";
> 
0
nick
2/13/2018 2:37:58 PM
Merlyn Kline <merlyn@binary.co.uk> writes:

> I'd like to set delegated attributes in my object constructors
> (e.g. as below) but this doesn't seem to work.  Am I missing
> something?

perldoc Moose::Manual::Delegation calls it "Attribute delegation", but
actually you're not delegating attributes. Instead, you are delegating
method calls to an attribute of your class.

So this is what you are missing: Calling Class->new simply isn't calling
$object->thing underneath.  If you add MooseX::StrictConstructor to your
package Class, it will barf at you saying

   Found unknown attribute(s) init_arg passed to the constructor: thing

BUILD or BUILDARGS can help to achieve what you're trying to do.
--
Cheers,
haj
0
Harald
2/13/2018 4:17:26 PM
--089e0825fe8cdec5ad05651c9dbb
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Thanks for quick and helpful replies. I'm not really trying to subvert
inheritance though I now see that my simplified example looks much like
that. I'd contemplated the BUILD(ARGS) route but couldn't see exactly how
to do it without losing some of the validation benefits (again, not really
visible in my simplified example). In my real code the composed in object
that I'm trying to delegate to is actually a lazily built DBIx result
object, FWIW.

I guess the problem here is that Moose doesn't really call the accessors in
the constructor but just uses some shortcut to copy the constructor
parameters to the object.

I think I'll look for a different solution. Or just stick with what I've
got now, where I call the accessors immediately after construction. Looks
ugly but there you go.

Thanks again,

Merlyn

On Tue, 13 Feb 2018 at 16:18 Harald J=C3=B6rg <Harald.Joerg@arcor.de> wrote=
:

> Merlyn Kline <merlyn@binary.co.uk> writes:
>
> > I'd like to set delegated attributes in my object constructors
> > (e.g. as below) but this doesn't seem to work.  Am I missing
> > something?
>
> perldoc Moose::Manual::Delegation calls it "Attribute delegation", but
> actually you're not delegating attributes. Instead, you are delegating
> method calls to an attribute of your class.
>
> So this is what you are missing: Calling Class->new simply isn't calling
> $object->thing underneath.  If you add MooseX::StrictConstructor to your
> package Class, it will barf at you saying
>
>    Found unknown attribute(s) init_arg passed to the constructor: thing
>
> BUILD or BUILDARGS can help to achieve what you're trying to do.
> --
> Cheers,
> haj
>
--=20

--=20
Merlyn

--089e0825fe8cdec5ad05651c9dbb
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Thanks for quick and helpful replies. I&#39;m not really t=
rying to subvert inheritance though I now see that my simplified example lo=
oks much like that. I&#39;d contemplated the BUILD(ARGS) route but couldn&#=
39;t see exactly how to do it without losing some of the validation benefit=
s (again, not really visible in my simplified example). In my real code the=
 composed in object that I&#39;m trying to delegate to is actually a lazily=
 built DBIx result object, FWIW.<div><br></div><div>I guess the problem her=
e is that Moose doesn&#39;t really call the accessors in the constructor bu=
t just uses some shortcut to copy the constructor parameters to the object.=
</div><div><br></div><div>I think I&#39;ll look for a different solution. O=
r just stick with what I&#39;ve got now, where I call the accessors immedia=
tely after construction. Looks ugly but there you go.</div><div><br></div><=
div>Thanks again,</div><div><br></div><div>Merlyn</div><div><br><div class=
=3D"gmail_quote"><div dir=3D"ltr">On Tue, 13 Feb 2018 at 16:18 Harald J=C3=
=B6rg &lt;<a href=3D"mailto:Harald.Joerg@arcor.de">Harald.Joerg@arcor.de</a=
>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0=
 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Merlyn Kline &lt;<a hr=
ef=3D"mailto:merlyn@binary.co.uk" target=3D"_blank">merlyn@binary.co.uk</a>=
&gt; writes:<br>
<br>
&gt; I&#39;d like to set delegated attributes in my object constructors<br>
&gt; (e.g. as below) but this doesn&#39;t seem to work.=C2=A0 Am I missing<=
br>
&gt; something?<br>
<br>
perldoc Moose::Manual::Delegation calls it &quot;Attribute delegation&quot;=
, but<br>
actually you&#39;re not delegating attributes. Instead, you are delegating<=
br>
method calls to an attribute of your class.<br>
<br>
So this is what you are missing: Calling Class-&gt;new simply isn&#39;t cal=
ling<br>
$object-&gt;thing underneath.=C2=A0 If you add MooseX::StrictConstructor to=
 your<br>
package Class, it will barf at you saying<br>
<br>
=C2=A0 =C2=A0Found unknown attribute(s) init_arg passed to the constructor:=
 thing<br>
<br>
BUILD or BUILDARGS can help to achieve what you&#39;re trying to do.<br>
--<br>
Cheers,<br>
haj<br>
</blockquote></div></div></div>-- <br><div dir=3D"ltr" class=3D"gmail_signa=
ture" data-smartmail=3D"gmail_signature"><div dir=3D"ltr"><p dir=3D"ltr">--=
 <br>
Merlyn<br></p>
</div></div>

--089e0825fe8cdec5ad05651c9dbb--
0
merlyn
2/13/2018 7:00:55 PM
Merlyn,

> I guess the problem here is that Moose doesn't really call the accessors in the constructor but just uses some shortcut to 
> copy the constructor parameters to the object.

While I fully admit that I've not been following this discussion closely, whenever I've seen a statement such as this one in 
the past, the answer usually comes back "take a look at triggers."  No idea if that's helpful or not, but I thought I'd throw 
it out there in case it was. :-)

Luck!


		-- Buddy
0
barefootcoder
2/14/2018 6:08:34 AM
Reply: