Skip Menu |

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

Report information
The Basics
Id: 21558
Status: resolved
Priority: 0/
Queue: Class-C3

People
Owner: blblack [...] gmail.com
Requestors: ted [...] tedcarnahan.com
Cc:
AdminCc:

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



Subject: Dispatch of methods bug
The test script should be very self-explanatory. When we call update_all on the Test::Recognition class, only the Fixture update_all method is called. If you add update_all methods to all of the classes, it works fine. The progressively begin commenting out update_all methods, beginning at the bottom of the file and working up. Everything still works fine until all of the update_all-s from Test::Class on are commented. Then only Fixture gets called. We think this is a bug, but would be happy to be informed otherwise. The MRO tree generated by visualize_c3.pl is also attached. It appears to be slightly incorrect ( there is no green link from Fixture::HasSubmission to Fixture::HasStudent ) but generally represents the structure correctly.
Subject: c3mro_bug.png
Download c3mro_bug.png
image/png 21.7k
c3mro_bug.png
Subject: c3mrotest.pl
package Class::Accessor; sub empty {} 1; package Fixture; use base 'Class::C3'; use base 'Class::Accessor'; sub update_all { # This is the only one that gets called. # It should be called third. print __PACKAGE__ . " called for update_all\n\n"; } 1; package Fixture::Scenario; use base 'Fixture'; 1; package Fixture::HasKnowledgeBase; use base 'Fixture'; 1; package Fixture::OneQNodeScenario; use base 'Fixture::HasKnowledgeBase'; use base 'Fixture::Scenario'; sub update_all { # We'd expect this to be called second, but it isn't print __PACKAGE__ . " called for update_all\n\n"; shift->next::method; } 1; package Fixture::HasKBSet; use base 'Fixture::HasKnowledgeBase'; 1; package Fixture::HasStudent; use base 'Fixture::HasKBSet'; 1; package Fixture::HasAssignment; use base 'Fixture::HasKBSet'; 1; package Fixture::HasAssignmentInstance; use base 'Fixture::HasAssignment'; use base 'Fixture::HasStudent'; 1; package Fixture::HasSubmission; use base 'Fixture::HasAssignmentInstance'; use base 'Fixture::HasStudent'; 1; package Fixture::HasEntry; use base 'Fixture::HasSubmission'; use base 'Fixture::OneQNodeScenario'; 1; package Fixture::TwoQNodeScenario; use base 'Fixture::OneQNodeScenario'; 1; package Fixture::Scenario::MeadsStages; use base 'Fixture::TwoQNodeScenario'; use base 'Fixture::HasEntry'; sub update_all { # We'd expect this to be called first, but it isn't print __PACKAGE__ . " called for update_all\n\n"; shift->next::method; } 1; package Fixture::ThreeQNodeScenario; use base 'Fixture::TwoQNodeScenario'; 1; package Fixture::Scenario::Theories; use base 'Fixture::ThreeQNodeScenario'; use base 'Fixture::Scenario::MeadsStages'; 1; package Test::Class; 1; package TestFixture; use base 'Test::Class'; use base 'Fixture'; 1; package Test::Recognition; use base 'TestFixture'; use base 'Fixture::Scenario::Theories'; 1; my $obj = new Test::Recognition; $obj->update_all;
From: BLBLACK [...] cpan.org
Hi Ted, Adding "use Class::C3" to each of the example classes in the test script, and then adding "Class::C3::initialize()" before constructing the test object (both of which come from the Class::C3 docs) seems to correct the behavior. Could you confirm this is the issue in your real code?
From: ted [...] tedcarnahan.com
On Mon Sep 18 18:13:41 2006, BLBLACK wrote: Show quoted text
> Adding "use Class::C3" to each of the example classes in the test > script, and then adding "Class::C3::initialize()" before constructing > the test object (both of which come from the Class::C3 docs) seems to > correct the behavior. Could you confirm this is the issue in your real > code?
This fixed our problem in the test code we provided earlier, but it didn't fix our real code. We did "use Class::C3" in all of the files in the hierarchy and initialized before constructing the test object, but without any success. We've finally boiled it down to this test case. As it stands when you run recog.pl, it will only run update_all from Fixture. But if you go into Fixture/HasKnowledgeBase.pm and comment the BEGIN block, it will successfully run update_all from all three classes. DB::Main, used in the BEGIN block, is a DBIx::Class schema. This seemed relevant because DBIx::Class uses Class::C3. Nevertheless, you'll note that none of the files included in this zip file inherit from that schema - they merely use it. Thanks for your continuing help with this.
Download related_to_dbic.zip
application/zip 4.7k

Message body not shown because it is not plain text.

As a temporary measure, could you try changing your Class::C3::initialize() call to Class::C3::reinitialize()? If that solves the problem, then at least we're on the right track.
Subject: Re: [rt.cpan.org #21558] Dispatch of methods bug
Date: Tue, 19 Sep 2006 14:22:12 -0500
To: bug-Algorithm-C3 [...] rt.cpan.org
From: Ted Carnahan <ted [...] tedcarnahan.com>
Preliminarily, it looks like we're making progress with reinitialize. We'll let you know when we've got everything ironed out on this end. - Ted
From: BLBLACK [...] cpan.org
On Tue Sep 19 15:22:28 2006, tedcarnahan wrote: Show quoted text
> Preliminarily, it looks like we're making progress with reinitialize. > We'll let you know when we've got everything ironed out on this end. >
If I'm on the right track and s/initialize/reinitialize/ in your code seems to fix things, then we should be able to fix this in Class::C3. The nature of the problem would be that the DBIx::Class code has already done a Class::C3::reinitialize() while your classes were half-defined (when the class that uses the schema was initialized), and then a plain initialize() call isn't clearing out the bad half-formed MRO that was generated then (whereas reinitialize() explicitly clears that out before recalculating everything). I'm not yet sure what the best fix is for this, there's a few different avenues we could go down in terms of code and/or API changes to Class::C3::[re]initialize().
From: ted [...] tedcarnahan.com
On Tue Sep 19 15:39:02 2006, BLBLACK wrote: Show quoted text
> If I'm on the right track and s/initialize/reinitialize/ in your code > seems to fix things, then we should be able to fix this in Class::C3. > The nature of the problem would be that the DBIx::Class code has already > done a Class::C3::reinitialize() while your classes were half-defined > (when the class that uses the schema was initialized), and then a plain > initialize() call isn't clearing out the bad half-formed MRO that was > generated then (whereas reinitialize() explicitly clears that out before > recalculating everything). I'm not yet sure what the best fix is for > this, there's a few different avenues we could go down in terms of code > and/or API changes to Class::C3::[re]initialize().
This seems very plausible. We have everything running correctly now, reinitialize was the key to getting it working. Thanks for your help working through this.
From: BLBLACK [...] cpan.org
This should fix the issue without any changes (init -> reinit for instance) on your part (hasn't gone to CPAN just yet): http://dtmf.com/Class-C3-0.14.tar.gz
From: ted [...] tedcarnahan.com
On Tue Sep 19 23:53:24 2006, BLBLACK wrote: Show quoted text
This fixes it, we can use initialize instead of reinitialize. Many thanks! - Ted Carnahan
Marking resolved as of 0.14