Closed ribasushi closed 8 years ago
Isn't this the kind of "Ugh, MRO being mystical and spicy" the sort of thing I was worried about earlier?
This is pretty much a direct result of the "use a linearized bottom-up refaddr check" logic you recommended.
perl -Ilib -It/lib -MDBICTest::Schema::Track -MScalar::Util=refaddr -E' say refaddr \&DBICTest::Schema::Track::delete; say refaddr \&DBIx::Class::InflateColumn::DateTime'
29246656
29247232
I guess what you want here is not a "refaddr matches previous" but "refaddr previously seen" thing ... but... that's going to lead to some false assumptions.
x -> isa y -> isa z
y::foo = sub {};
x::foo = z::foo = sub {};
Here reporting that x shadows y is "right".
However, if y is in isa like that due to tree flattening, then x does not shadow y.
I don't know how to resolve this ambiguity.
"refaddr matches previous" but "refaddr previously seen" thing
This is exactly it, yes: https://github.com/dbsrgits/dbix-class/blob/296248c3/lib/DBIx/Class/_Util.pm#L731-L735
However, if y is in isa like that due to tree flattening, then x does not shadow y.
Explain?
However, if y is in isa like that due to tree flattening, then x does not shadow y.
In your example:
I want to know what exactly is happening in the inheritance graph to make Perl have this happen.
perl -Ilib -It/lib -MANFANG -MDBICTest::Schema::Track -MScalar::Util=refaddr -E' printf "$_ => %s\n", $_->can(q[delete]) for qw( DBICTest::Schema::Track DBIx::Class::InflateColumn::DateTime DBIx::Class::Relationship::CascadeActions DBIx::Class::Ordered DBIx::Class::Row)'
DBICTest::Schema::Track => CODE(0x13ca5f0)
DBIx::Class::InflateColumn::DateTime => CODE(0x101fbe0)
DBIx::Class::Relationship::CascadeActions => CODE(0xec11c8)
DBIx::Class::Ordered => CODE(0x13ca5f0)
DBIx::Class::Row => CODE(0x101fbe0)
Because ::Track is comming from ::Ordered, but the fact all the inbetween entries are completely different seem to be ignored.
Obviously, this means "linearised isa is broken and meaningless".
On 06/07/2016 09:39 PM, Kent Fredric wrote:
Obviously, this means "linearised isa is broken and meaningless".
No, everything is correct as far as perl's behavior is concerned. I will write a more detailed explanation when my internet comes back.
Reduced subgraph of affected leaves in this interaction.
Now the same graph in MRO linear order is ...
WTF?
PS: I can see why you hate life now :P
Won't be able to get to you on this today, something else came up. Sorry for the delay.
The simplest way to explain my error that anyone else reading along can understand:
DBICTest::Schema::Track -> can("delete") --> \&DBIx::Class::Ordered::delete
|
DBIx::Class::InflateColumn::DateTime -> can("delete") --> \&DBIx::Class::Row::delete
|
DBIx::Class::Ordered -> can("delete") -> \&DBIx::Class::Ordered::delete
The real issue is using can
on ::DateTime brings the sub from DBIx::Class::Row forward to that point.
However, Perl itself does not work this way tracing methods from DBICTest::Schema::Track.
Instead, perl sees only this.
DBICTest::Schema::Track::delete = undef
|
DBIx::Class::InflateColumn::DateTime::delete = undef
|
DBIx::Class::Ordered::delete = sub { };
and resolves down that way, so that
DBICTest::Schema::Track
directly resolves to DBIx::Class::Ordered
.
This means ::DateTime
does not shadow DBIx::Class::Ordered
, and DBICTest::Schema::Track
does not shadow ::DateTime
Essentially this means using can
to determine whether or not a parent class provides a sub that shadows a lower sub is right out.
Because ->can()
on ::DateTime
would result in:
DBIx::Class::InflateColumn::DateTime::delete = undef
|
DBIx::Class::InflateColumn::Row::delete = undef
|
DBIx::Class::Row::delete = sub { };
Making DBIx::Class::Row::delete
return instead of undef
How we respect user defined "can" here is problematic.
I think the most "right" logic would be:
can
sub
can
sub == UNIVERSAL::can
can($sub)
returns that same subAs for how method resolution works if a parent class defines can
.... anybodies guess really.
I ran into this while working on a related feature, and tested D::I::E - it gets tricked in the same manner.
DBICTest::Schema::Track
does not define a delete(), it inherits it from elsewhere. The confusion happens because in the middle of the ISA there isDBIx::Class::Relationship::CascadeActions
which does not inherit from anything while providing a method for the consuming chain.The correct output of my (upcoming) tooling is:
Compare to: