mop problem 5 - Role and C3 searching is not always necessary

I think Role and C3 searching is not always necessary.

Object orientation good practice I want to tell to newbies is single inheritance and delegation.

Role is multiple inheritance. Role can have attributes. This mean role have data, not only methods. I don't think this is good.

I think the reason making mop complex is Role and C3 searching.

If Role and C3 searching are none, BUILD, BUILDARGS, DEMOLISH, $self->next::method, and many complex things is no needed. And overriding new method is easy and $self->SUPER::foo work well.

I don't deny Role and C3. TMTOWTDI is good, but are Role and C3 searching needed as core features?

Answer of comments

Multiple inheritance is bad, yes. But, why? Can you explain? (I don’t mean to me. Just think about it.)

The reason is that diamond inheritances occur in multiple inheritance. A -> B, A -> C, B -> D, C -> D.

You should find that for most of the problems of multiple inheritance, the answer is no. Roles are not multiple inheritance, in fact they are not inheritance at all.

.

I think role is limited multiple inheritance. Role can't inherit parent class. So diamond inheritance don't occur. but Role can have attribute values, not only methods. So I said role is a part of multiple inheritance.

BUILD and DEMOLISH have nothing to do with either roles, C3, or multiple inheritance. They are useful concepts even for normal single inheritance.

In single inheritance, we can call SUPER::foo, and DESTROY in order. This is simple. But Role have attribute values, so we need to initialize or finalize role attribute values if need.

I understand BUILD is to call all super class BUILD and role BUILD. DEMOLISH is to call all SUPER class and role DEMOLISH. This is wrong?

and I think this is called c3 order or reverse.

Single Inheritance itself is in my opinion always bad, that should be completly avoided. I also have written an article about the single inheritance problems here:

Single inheritance is good. Any modules can be created by single inheritance. If you need other class methods, you can use delegation.

class A {
  has c => C->new
}

class B {
has c => C->new
}

class C {

}

Roles are not multiple inheritance and in the MOP will not be implemented with multiple inheritance. You should do some reading up on Roles and how they work, I fear you do not understand them well enough.

the part I think it is problem is that role can attribute values. Ruby module can't have attribute values, but role can have attribute values. so I said role is a part of multiple inheritance.

If Role have attribute values, Role should have finalizer.

Is the system as Rule module is good? Ruby module can't have attribute value. why can role have attribute values?

Sorry, my understanding of role is not enough

Role is not relevant to multiple inheritance directory. Because mop can't work $self->SUPER::foo, and use $self->next::method, I had thought role is relevant to multiple inheritance.

I confirm role can be implemented on single inheritance. See the following code to confirm this. Combination of Role and $self->SUPER::baz work well.

test.pl
lib/role.pm
lib/SomeClass.pm
lib/BaseClass.pm
lib/TestRole1.pm
lib/TestRole2.pm

test.pl

use strict;
use warnings;
use lib 'lib';
use SomeClass;

my $c = SomeClass->new;
$c->foo;
$c->bar;
$c->baz;

1;

lib/role.pm

package role;

use strict;
use warnings;
use Carp 'croak';

sub import {
my ($self, @roles) = @_;

my $class = caller;

for my $role (@roles) {
eval "require $role";
croak $@ if $@;

my $role_file = $role;
$role_file =~ s/::/\//g;
$role_file .= ".pm";

my $role_path = $INC{$role_file};
open my $fh, '<', $role_path
or croak "Can't open file $role_path: $!";

my $role_content = do { local $/; <$fh> };

my $role_for_file = "role_for_$class";
$role_for_file =~ s/::/__/g;
$role_for_file .= "::$role";
$INC{$role_for_file} = undef;

my $role_for = $role_for_file;
$role_for =~ s/\//::/g;
$role_for =~ s/\.pm$//;

my $role_for_content = $role_content;
$role_for_content =~ s/package\s+(.+?);/package $role_for;/;
eval $role_for_content;

{
no strict 'refs';
my $parent = ${"${class}::ISA"}[0];
@{"${class}::ISA"} = ($role_for);
if ($parent) {
@{"${role_for}::ISA"} = ($parent);
}
}

croak $@ if $@;
}
}

our $VERSION = '0.01';

1;

lib/SomeClass.pm

package SomeClass;
use base 'BaseClass';
use role 'TestRole1', 'TestRole2';

sub baz {
my $self = shift;
print "SomeClass::baz\n";
return $self->SUPER::baz;
}

1;

lib/BaseClass.pm

package BaseClass;

use strict;
use warnings;

sub new {
my $class = shift;
my $self = shift;
return bless {}, $class;
};

sub baz {
my $self = shift;
print "BaseClass::baz\n";
}

1;

lib/TestRole1.pm

package TestRole1;

sub foo {
print "foo\n";
}

sub baz {
my $self = shift;

print "TestRole1::baz\n";
return $self->SUPER::baz;
}

1;

lib/TestRole2.pm

package TestRole1;

sub bar {
print "bar\n";
}

sub baz {
my $self = shift;
print "TestRole2::baz\n";
return $self->SUPER::baz;
}

1;


5 Comments

Multiple inheritance is bad, yes. But, why? Can you explain? (I don’t mean to me. Just think about it.)

Once you have done that, think about how roles work – or if you don’t know, find out. Then consider: can roles have the same problems as multiple inheritance?

You should find that for most of the problems of multiple inheritance, the answer is no. Roles are not multiple inheritance, in fact they are not inheritance at all. For example, C3 is not necessary for roles. It is only necessary for multiple inheritance. (So C3 could probably be left out. Maybe it should.)

BUILD and DEMOLISH have nothing to do with either roles, C3, or multiple inheritance. They are useful concepts even for normal single inheritance.

And I would argue that yes, absolutely roles should be a core feature. They give you the benefits that multiple inheritance promises, without the problems it causes. It is multiple inheritance that should be left out instead. Java tried this, but it only has interfaces, not roles, and interfaces are too limited, so it caused as many problems as it solved. Roles + single inheritance would be great.

(In fact you might be able to leave out inheritance completely and only have roles and classes. Even single inheritance has problems that roles do not have. But OK, let’s not get too experimental .)

Well, if you discipline yourself you can build a "Role-like" System with multiple inheritance. But it can easily go wrong. Role takes the good idea out of it and makes it nearly impossible to do it wrong.

Single Inheritance itself is in my opinion always bad, that should be completly avoided.

I also have written an article about the single inheritance problems here:

https://blogs.perl.org/users/sid_burn/2014/03/inheritance-is-bad-code-reuse-part-1.html

I try to continue the article the next days.

I can see why he's confused--in Perl, roles are often implemented via multiple inheritance under the hood. The other way to do it (off the top of my head) is to mess with the symbol table, which is a nastier solution.

That's an implementation detail, though. The semantic details of roles avoid the problems we usually associate with multiple inheritance. It's not a particularly leaky abstraction; you can pretend you have no idea how the implementation actually works and you'll be fine.

Roles are not multiple inheritance at all. In multiple inheritance, you're overloading class responsibility with code reuse and you introduce ordering problems (which C3 mitigates but does not solve).

Roles leave responsibility to the classes, but handle the code reuse. Further, unlike inheritance, they don't have ordering issues, ambiguities become compile-time failures, and they can be mixed and matched in any order without breaking (well, that's actually traits; Moose roles miss a few objectives here, but only in corner cases). I strongly suggest you read up more about roles/traits to better understand them.

I and many other developers are gradually coming to the conclusion that if we had to choose between inheritance and roles, we'd choose roles.

C3 will not be part of the MOP, it is part of the core of Perl already, it will be possible for a user of the MOP to use C3 just as it is possible for a user to do that with regular Perl OO.

Roles are not multiple inheritance and in the MOP will not be implemented with multiple inheritance. You should do some reading up on Roles and how they work, I fear you do not understand them well enough.

Leave a comment

About Yuki Kimoto

user-pic I'm Perl Programmer. I LOVE Perl. I want to contribute Perl community and Perl users.