Skip Menu |

This queue is for tickets about the Moose CPAN distribution.

Report information
The Basics
Id: 40968
Status: resolved
Priority: 0/
Queue: Moose

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

Bug Information
Severity: Normal
Broken in: 0.61
Fixed in: 0.62_02



Subject: Inherited constructor is silently masked by make_immutable
An inherited new() is silently masked by make_immutable in the derived class. I realize that BUILD, etc. are preferred to new(), but in this case I had a good reason to override new(), and it took me a while to figure out why my inherited new() wasn't being called. Test attached.
Subject: 010_inherited_constructor.t
#!/usr/bin/perl use strict; use warnings; use Test::More tests => 1; =pod This tests that an inherited constructor will not be masked by make_immutable. =cut { package Foo; use Moose; our $new_called = 0; sub new { $new_called = 1; } } { package Bar; use Moose; extends 'Foo'; Bar->meta->make_immutable(); } Bar->new(); ok($Foo::new_called, "Foo::new was called");
Subject: Re: [rt.cpan.org #40968] Inherited constructor is silently masked by make_immutable
Date: Sun, 16 Nov 2008 00:12:09 -0600 (CST)
To: JSWARTZ via RT <bug-Moose [...] rt.cpan.org>
From: Dave Rolsky <autarch [...] urth.org>
On Sun, 16 Nov 2008, JSWARTZ via RT wrote: Show quoted text
> Sun Nov 16 00:15:55 2008: Request 40968 was acted upon. > Transaction: Ticket created by JSWARTZ > Queue: Moose > Subject: Inherited constructor is silently masked by make_immutable > Broken in: 0.61 > Severity: Normal > Owner: Nobody > Requestors: JSWARTZ@cpan.org > Status: new > Ticket <URL: http://rt.cpan.org/Ticket/Display.html?id=40968 > > > > An inherited new() is silently masked by make_immutable in the derived > class. I realize that BUILD, etc. are preferred to new(), but in this > case I had a good reason to override new(), and it took me a while to > figure out why my inherited new() wasn't being called.
This is pretty much what make_immutable is all about, and in fact this issue is one of the main reasons we tell people to not to override new(). If you _really_ want to override new and use make_immutable, you can provide your own immutable constructor class that replicates your new() method. This is, obviously, a pain in the ass, but it's doable. Fey::ORM has an example of this. But this is definitely not a bug. -dave /*============================================================ http://VegGuide.org http://blog.urth.org Your guide to all that's veg House Absolute(ly Pointless) ============================================================*/
Subject: Re: [rt.cpan.org #40968] Inherited constructor is silently masked by make_immutable
Date: Sun, 16 Nov 2008 01:46:10 -0500
To: bug-Moose [...] rt.cpan.org
From: Sartak <sartak [...] gmail.com>
On Sun, Nov 16, 2008 at 1:12 AM, autarch@urth.org via RT <bug-Moose@rt.cpan.org> wrote: Show quoted text
>> An inherited new() is silently masked by make_immutable in the derived >> class. I realize that BUILD, etc. are preferred to new(), but in this >> case I had a good reason to override new(), and it took me a while to >> figure out why my inherited new() wasn't being called.
> > This is pretty much what make_immutable is all about, and in fact this > issue is one of the main reasons we tell people to not to override new().
Sometimes you must inherit it from a non-Moose class. Show quoted text
> If you _really_ want to override new and use make_immutable, you can > provide your own immutable constructor class that replicates your new() > method. This is, obviously, a pain in the ass, but it's doable.
Passing inline_constructor => 0 to make_immutable is probably good enough (it was for me! :)). Show quoted text
> > Fey::ORM has an example of this. > > But this is definitely not a bug.
Agreed. It might be useful to warn in this instance though. I've been bitten by the same thing. If the "new" is not provided by Moose::Object, then we could warn if there's an *implicit* inline_constructor => 1. Explicitly saying inline_constructor => 1 would silence the warning, because presumably you know what you're doing. I figure many users of Moose are just cargo culting the make_immutable as an easy way to speed up the class, without knowing what it's actually doing. Show quoted text
> -dave
Shawn
On Sun Nov 16 01:46:22 2008, SARTAK wrote: Show quoted text
> On Sun, Nov 16, 2008 at 1:12 AM, autarch@urth.org via RT
> > > > But this is definitely not a bug.
I agree completely. Show quoted text
> Agreed. It might be useful to warn in this instance though. I've been > bitten by the same thing. If the "new" is not provided by > Moose::Object, then we could warn if there's an *implicit* > inline_constructor => 1. Explicitly saying inline_constructor => 1 > would silence the warning, because presumably you know what you're > doing.
I like this idea, it seems a reasonable compromise. - Stevan
Show quoted text
> Passing inline_constructor => 0 to make_immutable is probably good > enough (it was for me! :)).
Cool. Is this documented somewhere? The only documentation I could find for make_immutable was Recipe7, which doesn't mention this. Show quoted text
>
> > > > Fey::ORM has an example of this. > > > > But this is definitely not a bug.
> > Agreed. It might be useful to warn in this instance though. I've been > bitten by the same thing. If the "new" is not provided by > Moose::Object, then we could warn if there's an *implicit* > inline_constructor => 1. Explicitly saying inline_constructor => 1 > would silence the warning, because presumably you know what you're > doing. > > I figure many users of Moose are just cargo culting the make_immutable > as an easy way to speed up the class, without knowing what it's > actually doing.
Guilty as charged. But I shouldn't HAVE to understand how make_immutable is implemented to use it. make_immutable is essentially documented as "this will speed up your class, but in return you can't make changes to the metaclass afterwards". I followed those rules, and still got bitten, because I assumed that basic OO rules (like constructor inheritance) would not be affected. Sounds like Shawn got bitten too. I expect then that many others will also get bitten. If this behavior remains, as it sounds like it will, then there should definitely at least be a warning, and something in the docs about "this will ignore inherited constructors." What makes this worse is that you *can* override new() in the class itself, just not in its parents. If make_immutable were really "all about" inlining the constructor (it isn't - it's also about speeding up attributes), then make_immutable ought to fail if there is a new() already defined. Show quoted text
> This issue is one of the main reasons we tell people to not to > override new().
I didn't know that. I did know that overriding new() is strongly discouraged, but as I said, I had a legitimate reason to override new() in this case.
On Sun Nov 16 08:51:03 2008, JSWARTZ wrote: Show quoted text
> > Passing inline_constructor => 0 to make_immutable is probably good > > enough (it was for me! :)).
> > Cool. Is this documented somewhere? The only documentation I could find > for make_immutable was Recipe7, which doesn't mention this.
It should be mentioned in the Moose::Cookbook::WTF, there is a whole section on the evils of overriding new() in there (http://search.cpan.org/~drolsky/Moose- 0.61/lib/Moose/Cookbook/WTF.pod#Constructors_&_Immutability) Show quoted text
> >
> > > > > > Fey::ORM has an example of this. > > > > > > But this is definitely not a bug.
> > > > Agreed. It might be useful to warn in this instance though. I've been > > bitten by the same thing. If the "new" is not provided by > > Moose::Object, then we could warn if there's an *implicit* > > inline_constructor => 1. Explicitly saying inline_constructor => 1 > > would silence the warning, because presumably you know what you're > > doing. > > > > I figure many users of Moose are just cargo culting the make_immutable > > as an easy way to speed up the class, without knowing what it's > > actually doing.
> > Guilty as charged. But I shouldn't HAVE to understand how make_immutable > is implemented to use it.
Agreed, however I think all you need to understand here (and unfortunately it doesnt seem to be documented clearly anywhere) that immutable creates an inlined constructor for you, which means it will create a local ->new() which obviously will override. Show quoted text
> make_immutable is essentially documented as > "this will speed up your class, but in return you can't make changes to > the metaclass afterwards". I followed those rules, and still got bitten, > because I assumed that basic OO rules (like constructor inheritance) > would not be affected. Sounds like Shawn got bitten too. I expect then > that many others will also get bitten.
I won't disagree that it can be surprising, however it is not breaking basic OO rules because it is creating a local ->new(), this it the trade off. Show quoted text
> If this behavior remains, as it sounds like it will, then there should > definitely at least be a warning, and something in the docs about "this > will ignore inherited constructors."
We can detect an inherited constructor so we can basically just warn in the specific circumstance, Shawn mentioned that above. Show quoted text
> What makes this worse is that you *can* override new() in the class > itself, just not in its parents. If make_immutable were really "all > about" inlining the constructor (it isn't - it's also about speeding up > attributes), then make_immutable ought to fail if there is a new() > already defined.
Actually, that line in the docs is kind of misleading, because Moose already inlines the accessors for you by default. So immutability has little affect on the accessors and almost all of the benefit is in the constructors. Show quoted text
> > This issue is one of the main reasons we tell people to not to > > override new().
> > I didn't know that. I did know that overriding new() is strongly > discouraged, but as I said, I had a legitimate reason to override new() > in this case.
Can you explain that reason? Perhaps there is a (poorly documented) feature that exists that we can point you too. Between BUILD, BUILDARGS, attribute defaults, attribute builders and attribute laziness there are very few good reasons left actually. - Stevan
CC: JSWARTZ [...] cpan.org
Subject: Re: [rt.cpan.org #40968] Inherited constructor is silently masked by make_immutable
Date: Mon, 24 Nov 2008 12:42:58 -0800
To: bug-Moose [...] rt.cpan.org
From: Jonathan Swartz <swartz [...] pobox.com>
Show quoted text
>>> >>> This issue is one of the main reasons we tell people to not to >>> override new().
>> >> I didn't know that. I did know that overriding new() is strongly >> discouraged, but as I said, I had a legitimate reason to override >> new() >> in this case.
> > Can you explain that reason? Perhaps there is a (poorly documented) > feature that exists that we can > point you too. Between BUILD, BUILDARGS, attribute defaults, > attribute builders and attribute laziness > there are very few good reasons left actually. >
Well, to be honest, it was because we are using an old version of Moose that doesn't have BUILDARGS. So upgrading would fix this. I still think people will override new some of the time, whether or not it is truly necessary. Anyway, thanks for your reasonable responses. Jon
Subject: Re: [rt.cpan.org #40968] Inherited constructor is silently masked by make_immutable
Date: Tue, 25 Nov 2008 06:44:31 +0200
To: bug-Moose [...] rt.cpan.org
From: "Yuval Kogman" <nothingmuch [...] woobling.org>
if ( $class->can("new") == "Moose::Object"->can("new") ) { # make an immutable constructor }