Skip Menu |

This queue is for tickets about the Class-Std CPAN distribution.

Report information
The Basics
Id: 14048
Status: new
Priority: 0/
Queue: Class-Std

People
Owner: Nobody in particular
Requestors: aparker42 [...] gmail.com
Cc:
AdminCc:

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



Subject: Coercions fail if the object is created during BEGIN
It appears that the patch to make the coercions polymorphic caused other problems: Operation `""': no method found, argument in overloaded package Problem at t/begin-coercion.t line 24. If an class does its own "use overload" as well as using the Class::Std coercion attributes and the only instance of the object is created during BEGIN time then the coercions won't work. This appears to be result of the way the overload module works. The coercions from Class::Std don't get properly registered in the %OVERLOAD hash (I'm guessing it is because the code to do the overloads is eval'd in the CHECK phase). A bless of the class will cause the %OVERLOAD to be properly populated, but in this case since the only bless happened at BEGIN before the coercions were in place %OVERLOAD isn't updated. I've come up with one fix for this: after the coercions for a package have been put in place in the CHECK block in Class::Std simply do "bless {}, $package;". It works, but just seems wrong. Maybe overload provides a better way of forcing the %OVERLOAD hash to be updated? Andrew Parker
use Test::More 'no_plan'; package Problem; use Class::Std; # overload seems to interfere as well (remove this and it works) use overload '+' => sub {}; sub as_string : STRINGIFY { return 'string'; } package main; our $obj; BEGIN { $obj = Problem->new(); } # use of stringification is what shows the problem # if another Problem object is created later thowgh, this # stringification will work # Uncomment next line and this will work #Problem->new(); ok("$obj");
From: aparker42 [...] gmail.com
Well, after looking into it some more I couldn't find any better way to get it to work. I changed from using a hashref to an arrayref just to make it a little lighter weight (I suppose it could also just use ref to a scalar). Attached is the patch including a test Andrew Parker
diff -uNr Class-Std-0.0.4/MANIFEST Class-Std-0.0.4-fix-begin/MANIFEST --- Class-Std-0.0.4/MANIFEST Sat Aug 6 21:13:29 2005 +++ Class-Std-0.0.4-fix-begin/MANIFEST Tue Aug 9 20:35:30 2005 @@ -23,3 +23,4 @@ t/simple.t t/dump.t t/access.t +t/begin-coercion.t diff -uNr Class-Std-0.0.4/lib/Class/Std.pm Class-Std-0.0.4-fix-begin/lib/Class/Std.pm --- Class-Std-0.0.4/lib/Class/Std.pm Sat Aug 6 21:19:22 2005 +++ Class-Std-0.0.4-fix-begin/lib/Class/Std.pm Tue Aug 9 20:30:23 2005 @@ -354,6 +354,10 @@ eval sprintf $OVERLOADER_FOR{$attr}, ($package)x2; die "Internal error: $@" if $@; } + # The overloads don't take effect until the next bless so we + # need to bless here to make sure that if an object was blessed + # before this CHECK runs that it will still be able to get the overloads + bless [], $package; delete $overload{$package}; } } diff -uNr Class-Std-0.0.4/t/begin-coercion.t Class-Std-0.0.4-fix-begin/t/begin-coercion.t --- Class-Std-0.0.4/t/begin-coercion.t Wed Dec 31 16:00:00 1969 +++ Class-Std-0.0.4-fix-begin/t/begin-coercion.t Tue Aug 9 20:40:52 2005 @@ -0,0 +1,20 @@ +# If a single object is created during begin then the coercions should work +# later. + +use Test::More 'no_plan'; + +package Problem; +use Class::Std; + +# an overload here is also needed to make the problem show up +use overload '+' => sub {}; +sub as_string : STRINGIFY { return 'string'; } + +package main; + +my $obj; +BEGIN { + $obj = Problem->new(); +} + +ok("$obj");
From: aparker42 [...] gmail.com
That fix doesn't fully work. I've discovered that subclasses don't work correctly with it. It seems that the overload information is stored in each class in the heirarchy and so the subclasses will need to be blessed as well. The only way I can think of that is to bless something into every package available in the system. That solution doesn't seem very good, though. I can't think of why it wouldn't work, but it just seems ugly.