Skip Menu |

This queue is for tickets about the Moo CPAN distribution.

Report information
The Basics
Id: 91326
Status: rejected
Priority: 0/
Queue: Moo

People
Owner: Nobody in particular
Requestors: djerius [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: overloading %{} breaks constructor
I'd like to have my objects return a hash when explicitly dereferenced, so I tried something like this: ------------------------------ package Party; use Moo; use overload '%{}' => sub { { tea => $_[0]->tea } }; has tea => ( is => 'rw' ); package main; use Data::Dumper; my %hash = %{ Party->new( tea => 'Gunpowder' ) }; print Dumper \%hash; ------------------------------ Unfortunately, this is the output: % perl hash.pl $VAR1 = { 'tea' => undef }; If I comment out the overload line, I get % perl hash.pl $VAR1 = { 'tea' => 'Gunpowder' }; which is the expected result, but isn't really production code worthy, as I have to assume something about the object's underlying storage mechanism. Thanks, Diab
Subject: Re: [rt.cpan.org #91326] overloading %{} breaks constructor
Date: Wed, 11 Dec 2013 10:54:33 -0800
To: Diab Jerius via RT <bug-Moo [...] rt.cpan.org>
From: Karen Etheridge <ether [...] cpan.org>
On Wed, Dec 11, 2013 at 11:53:40AM -0500, Diab Jerius via RT wrote: Show quoted text
> I'd like to have my objects return a hash when explicitly dereferenced, so I tried something like this:
... Show quoted text
> which is the expected result, but isn't really production code worthy, as I have to assume something about the object's underlying storage mechanism.
You shouldn't assume anything about the object's underlying storage mechanism -- that's locked away in an abstraction. Instead, you should implement a ->serialize method that will give you the underlying data. In Moose, this would be done with MooseX::Storage - I'm not sure if there is an equivalent in Moo, but if there isn't, the design of this module should point you in the right direction to roll your own.
On Wed Dec 11 13:54:49 2013, ETHER wrote: Show quoted text
> On Wed, Dec 11, 2013 at 11:53:40AM -0500, Diab Jerius via RT wrote:
> > I'd like to have my objects return a hash when explicitly > > dereferenced, so I tried something like this:
> ...
> > which is the expected result, but isn't really production code > > worthy, as I have to assume something about the object's underlying > > storage mechanism.
> > You shouldn't assume anything about the object's underlying storage > mechanism -- that's locked away in an abstraction.
Perhaps my original point got lost. I would like to overload %{}. If I do, Moo's constructor breaks. I *know* not to assume anything about internal storage, hence my comment about using %$object without the overload not being production ready code.
Subject: Re: [rt.cpan.org #91326] overloading %{} breaks constructor
Date: Wed, 11 Dec 2013 15:00:28 -0800
To: Diab Jerius via RT <bug-Moo [...] rt.cpan.org>
From: Karen Etheridge <ether [...] cpan.org>
On Wed, Dec 11, 2013 at 05:11:43PM -0500, Diab Jerius via RT wrote: Show quoted text
> I would like to overload %{}. If I do, Moo's constructor breaks.
Overloading %{} on an object implies that you are aware that it is implemented as a blessed hash, which you shouldn't assume. If you want to get a serialized form of the object, then implement a sanely-named method, rather than expecting %{} to do what you mean.
Subject: Re: [rt.cpan.org #91326] overloading %{} breaks constructor
Date: Thu, 12 Dec 2013 00:26:29 +0100
To: bug-Moo [...] rt.cpan.org
From: ilmari [...] ilmari.org (Dagfinn Ilmari Mannsåker)
"Diab Jerius via RT" <bug-Moo@rt.cpan.org> writes: Show quoted text
> I would like to overload %{}. If I do, Moo's constructor breaks.
Not just the constructor, but _all_ of Moo's internal access to the attributes (except for accessors provided by Class::XSAccessor, since it ignores overloading), The constructor and perl accessors are all generated by Sub::Quote, so just returning the object itself if that's the caller would work, but that also assumes too much about Moo internals. -- "I use RMS as a guide in the same way that a boat captain would use a lighthouse. It's good to know where it is, but you generally don't want to find yourself in the same spot." - Tollef Fog Heen
On Wed Dec 11 18:00:42 2013, ETHER wrote: Show quoted text
> On Wed, Dec 11, 2013 at 05:11:43PM -0500, Diab Jerius via RT wrote:
> > I would like to overload %{}. If I do, Moo's constructor breaks.
> > Overloading %{} on an object implies that you are aware that it is > implemented as a blessed hash, which you shouldn't assume.
Overloading %{} means only one thing: I want to specify a behavior when the object is used in a context expecting a hash. There are no assumptions about the underlying storage. It could be a blessed array, a connection to a database, anything. As an example, here's an object which uses a blessed array. --------------------------------------------- package Foo; use overload "%{}", sub { my $self = shift; return { map { ("index:$_", $self->[$_]) } 0..(@$self-1) } }; sub new { my ( $class, @args ) = @_; return bless \@args, $class; } package main; my $foo = Foo->new( 2, 4, 6, 8 ); use Data::Dumper; print Dumper {%$foo}; --------------------------------------------- This is no different than overloading "" for stringification of an object.
CC: undisclosed-recipients:;
Subject: Re: [rt.cpan.org #91326] overloading %{} breaks constructor
Date: Thu, 12 Dec 2013 00:31:17 +0100
To: bug-Moo [...] rt.cpan.org
From: ilmari [...] ilmari.org (Dagfinn Ilmari Mannsåker)
"Karen Etheridge via RT" <bug-Moo@rt.cpan.org> writes: Show quoted text
> Queue: Moo > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=91326 > > > On Wed, Dec 11, 2013 at 05:11:43PM -0500, Diab Jerius via RT wrote:
>> I would like to overload %{}. If I do, Moo's constructor breaks.
> > Overloading %{} on an object implies that you are aware that it is > implemented as a blessed hash, which you shouldn't assume.
No, overloading %{} implies that you want users to be able to use it as a hashref regardless of the implementation. The problem is that the overload also applies when Moo itself accesses the hash. One workaround is to use MooX::InsideOut, which doesn't use a blessed hashref, but instead a scalarref as a key to a fieldhash. Show quoted text
> If you want to get a serialized form of the object, then implement a > sanely-named method, rather than expecting %{} to do what you mean. > >
-- "The surreality of the universe tends towards a maximum" -- Skud's Law "Never formulate a law or axiom that you're not prepared to live with the consequences of." -- Skud's Meta-Law
On Wed Dec 11 11:53:38 2013, DJERIUS wrote: Show quoted text
> I'd like to have my objects return a hash when explicitly > dereferenced, so I tried something like this: > > ------------------------------ > > package Party; > > use Moo; > > use overload '%{}' => sub { { tea => $_[0]->tea } }; > > has tea => ( is => 'rw' ); > > package main; > > use Data::Dumper; > > my %hash = %{ Party->new( tea => 'Gunpowder' ) }; > > print Dumper \%hash; > > ------------------------------ > > > Unfortunately, this is the output: > > % perl hash.pl > $VAR1 = { > 'tea' => undef > }; > > > If I comment out the overload line, I get > > % perl hash.pl > $VAR1 = { > 'tea' => 'Gunpowder' > }; > > > which is the expected result, but isn't really production code worthy, > as I have to assume something about the object's underlying storage > mechanism. > > Thanks, > > Diab
I don't think it's reasonable to have Moo itself try to make this work. Two possible workarounds: 1. use MooX::InsideOut 2. Write a MooX module that wraps various code bits in "do { no overloading; ... }"
On Wed Dec 11 11:53:38 2013, DJERIUS wrote: Show quoted text
> Unfortunately, this is the output:
Yes, because overloading %{} on a hashref-based object is obviously broken. Show quoted text
> If I comment out the overload line, I get > > % perl hash.pl > $VAR1 = { > 'tea' => 'Gunpowder' > }; > > > which is the expected result, but isn't really production code worthy, > as I have to assume something about the object's underlying storage > mechanism.
No, you don't. The problem here is you *are* making assumptions about the implementation. The object's API can include "%{} does the right thing" . This is fine. External code should *not* need to know that overloading is being used to provide that API - as such, the version without overloading is *correct*. If, later, you change to a non-hashref internal structure, at that point you would use operator overloading to maintain the API. There is no bug in Moo here, merely a misunderstanding of encapsulation on your part. As such, I'm marking this ticket invalid - if you want to discuss OO design, please feel free to do so with us on IRC.
On Wed Dec 11 19:03:29 2013, MSTROUT wrote: Show quoted text
> On Wed Dec 11 11:53:38 2013, DJERIUS wrote:
> > Unfortunately, this is the output:
> > Yes, because overloading %{} on a hashref-based object is obviously > broken.
But it seems possible to fix that, if that were so desired. How about this? sub new { my ( $class, %args ) = @_; return bless \{%args}, $class; } This retains the hash nature of the object, but hides it from the overloading magic. The attribute accessors would obviously have to be changed to handle an extra layer of indirection, but that would be transparent to the end user. All other method calls should work the same. Show quoted text
>
> > If I comment out the overload line, I get > > > > % perl hash.pl > > $VAR1 = { > > 'tea' => 'Gunpowder' > > }; > > > > > > which is the expected result, but isn't really production code > > worthy, > > as I have to assume something about the object's underlying storage > > mechanism.
> > No, you don't. The problem here is you *are* making assumptions about > the implementation.
Unfortunately, it seems no one is intepreting the sentence I wrote in the way that I meant it, and it is leading to many assumptions. Since it really has little bearing on the actual subject of this discussion, I'd suggest we just ignore it and move on. Show quoted text
> The object's API can include "%{} does the right thing" . This is > fine. External code should *not* need to know that overloading is > being used to provide that API - as such, the version without > overloading is *correct*.
I don't think that such a statement would be valid. Since Moo doesn't document its implementation, the result of applying %{} to a Moo based object is technically undefined, and so no guarantees may be made about it. While I may know that Moo is hash based, I can't in good faith use that knowledge if it isn't part of its published API. (I can't find any mention of that in the Moo documentation; perhaps I missed it). Show quoted text
> There is no bug in Moo here, merely a misunderstanding of > encapsulation on your part.
I misunderstand many, many things in life.