http://www.perlmonks.org?node_id=385083


in reply to Re^3: Solving compositional problems with Perl 6 roles
in thread Solving compositional problems with Perl 6 roles

I think the relevant part of A12 is:

Class Composition with Roles

Objects have many kinds of relationships with other objects. One of the pitfalls of the early OO movement was to encourage people to model many relationships with inheritance that weren't really "isa" relationships. Various languages have sought to redress this deficiency in various ways, with varying degrees of success. With Perl 6 we'd like to back off a step and allow the user to define abstract relationships between classes without committing to a particular implementation.

More specifically, we buy the argument of the Traits paper that classes should not be used both to manage objects and to manage code reuse. It needs to be possible to separate those concerns. Since a lot of the code that people want to reuse is that which manages non-isa object relationships, that's what we should abstract out from classes.

That abstraction we are calling a role. Roles can encompass both interface and implementation of object relationships. A role without implementation degenerates to an interface. A role without interface degenerates to privately instantiated generics. But the typical role will provide both interface and at least a default implementation.

Unlike the Traits paper, we will allow state as part of our implementation. This is necessary if we are to abstract out the delegation decision. We feel that the decision to delegate rather than compose a sub-object is a matter of implementation, and therefore that decision should be encapsulated (or at least be allowed to be encapsulated) in a role. This allows you to refactor a problem by redefining one or more roles without having to doctor all the classes that make use of those roles. This is a great way to turn your huge, glorious "god object" into a cooperating set of objects that know how to delegate to each other.

As in the Traits paper, roles are composed at class construction time, and the class composer does some work to make sure the composed class is not unintentionally ambiguous. If two methods of the same name are composed into the same class, the ambiguity will be caught. The author of the class has various remedies for dealing with this situation, which we'll go into below.

From the standpoint of the typical user, a role just looks like a "smart" include of a "partial class". They're smart in that roles have to be well behaved in certain respects, but most of the time the naive user can ignore the power of the abstraction.

The enboldened (my highlighting) part in the last paragraph forms the mental model that I am using.

In effect, the "smart include" means that there is no inheritance involved--although another part of a12 goes on to say that it maybe implemented using a form of MI at the Parrot level--the Role's methods actually become a part of the Class(es) to which they are applied when used in the compile-time form. Where the does is applied to the class itself, and applies to all instances of that class.

In the runtime form, where the Role is applied to an instance of some class, only that instance gains the new methods. In implementation, a new anonymous class is created that is the composition of that instance' class and the Role.

I take this to mean that if a Role is applied to an instance of class Dog at runtime, and the the Class Dog was subsequently modified (through introspection for example), the instance that had the Role applied at runtime, would continue to be based on the original version, not the modified version of Dog.

In the end, I doubt that these details will have any great significance in use. I can imagine there being a Storable Role that know how to copy an instance' attributes to and from disk without needing to know much of anything about the Class of instance to which it is applied. If you have have (or get from somewhere) a class that does what you need, but you need to be able to save and restore the instances, you apply the Storable Role to it. At compile time of all instances need it. At runtime if only some instances need it.

The Storable Role would be defined as an interface (or perhaps with a minimal implementation). Then you (your site) provide an implementation of the defined interface that meets your requirements: Flat files, Berkeley, RDBMS of some flavour, OODB. The interface might be defined to have two methods: .freeze :id; and .thaw :id;. Switching DB vendors becomes a case of installing their implementation of the Storable Role, and everything else continues as is.

Or maybe that would be better implemented as a Trait? There is so much in A12 it's hard to put your finger on what wil become best practice.


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon