Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Re: Possible issue with Moose ScalarRef

by tobyink (Canon)
on Jan 10, 2013 at 20:23 UTC ( [id://1012737]=note: print w/replies, xml ) Need Help??


in reply to Possible issue with Moose ScalarRef

I agree; this seems broken. Small test case...

use strict; use warnings; use Test::More; { package Thing; use Moose; has attr => (is => 'ro'); } { package ThingWithRef; use Moose; has attr => (is => 'ro'); sub translate_to_dutch { my $self = shift; ${ $self->attr } =~ s/e/a/; } } my $obj1 = Thing->new(attr => 'Hello'); my $obj2 = ThingWithRef->new(attr => \$obj1->attr); $obj2->translate_to_dutch; is($obj1->attr, 'Hallo'); done_testing;

If you use Moo instead of Moose, then things work as expected.

UPDATE: OK, not a bug. It's just that the reference \$obj1->attr is not guaranteed to be a reference to the slot within the object. So changing data via the reference will not necessarily effect $obj1. If it works, it works; if not, then it won't; no guarantees. Currently it works in Moo but not Moose, but the situation - in either - could change.

If you want what you want (for both objects to have access to the same piece of data) then you need it to be a scalar ref in both classes.

UPDATE 2: It also fails in Moo if Moo is in pure Perl mode (not XS).

perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

Replies are listed 'Best First'.
Re^2: Possible issue with Moose ScalarRef
by greengaroo (Hermit) on Jan 11, 2013 at 15:12 UTC

    Thanks for all your tests! It means I'm not crazy! But that is a very strange behavior!

    You mentioned "changing data via the reference", I want to do the opposite in fact, changing the data in the original variable so I can reference to it from another object. I guess the result is the same.

    Anyway, I found a workaround, and it seems to do what I want, but I still have a different SCALAR address for the original and the reference. I now do this:

    my $obj = Something->new( { # Before: #'debug_level' => \$self->debug_level, # Now: 'debug_level' => \$self->{'debug_level'}, } );

    Do you think it would always work, or is it "random" like the previous way?

    Testing never proves the absence of faults, it only shows their presence.

      It will work for objects which are internally implemented as hashrefs. Moose does this by default, and it's quite a bit of work to persuade it to implement objects any other way.

      (There are various MooseX modules on CPAN that can do that work for you, including MooseX::InsideOut and my own MooseX::ArrayRef which allows you to create Moose classes based on arrayrefs.)

      It is generally considered poor style to peek at the hashref internals of Moose objects (indeed, blessed objects in general). One good reason is that if you're relying on a module's internals, it gives the module's author less freedom to refactor those internals.

      In this case, when you appear to be the author of both modules, so the above might not be a concern, the strong argument against poking the hashref is that it bypasses type constraint checks.

      One alternative solution might be to pass a closure from your first class to your second class...

      use strict; use warnings; use Test::More; { package Thing; use Moose; has attr => (is => 'rw'); sub get_closure { my $self = shift; return sub { $self->attr(@_) }; } } { package ThingWithRef; use Moose; has closure => (is => 'ro'); sub translate_to_dutch { my $self = shift; my $str = $self->closure->(); $str =~ s/e/a/; $self->closure->($str); } } my $obj1 = Thing->new(attr => 'Hello'); my $obj2 = ThingWithRef->new(closure => $obj1->get_closure); $obj2->translate_to_dutch; is($obj1->attr, 'Hallo'); done_testing;
      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

        Thanks again! I will think about it and find the best, long-term solution.

        Testing never proves the absence of faults, it only shows their presence.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1012737]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (5)
As of 2024-04-20 01:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found