Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

Hello gaal, Ovid pointed me to this discussion, and since I am the author of Class::Trait, I thought I might pipe up and answer some of your questions.

Traits are like interfaces in that they provide a way for a class to promise it fulfills some {interface, protocol} — that is, to say "I can do this".

Actually, I think you need to invert your thinking on that. To start with, Traits aren't really classes, and to think of them as such may get you into trouble with them. And to think of Traits as being too much like interfaces and mix-ins, might also lead to problems. Traits are more akin to "deferred classes" as found in Eiffel. They are not meant to be complete, or to be able to stand on their own, they are building blocks for classes, but not really classes themselves. This node includes some documentation I originally wrote for Class::Trait, but ended up not including, it describes a formal langauge/calculus for traits (ripped off from on of the papers, I certainly didn't come up with that myself).

But, anyway, back to the point. Traits themselves have requirements which must be fufilled by the class that chooses to use them. After the requirement is fufilled, and the trait is flattened into the class, nothing else happens. I did however, implement a is method into Class::Trait, which is added to the class using the traits. This is to be thought of being like isa is in perl, it will do a depth-first search of all the traits the class has used and return true of false depending upon whether the class used that trait.

But here is where Traits differ from interfaces/protocols. After the class has used the trait,and it is incorporated, to all outside parties it is like nothing ever happened, and you implemented the methods yourself in the class directly. There is no implied contract between the class which used the traits and any other object in your system.

They are like a base class in that the trait itself can provide some implementation code of its own.

Again, best to not thing of Traits as classes. They are simply a set of methods collected into a grouping, which can be added into a class. Other than that though your statement is correct.

Unlike interfaces and base classes, but like mix-ins, all entities are pushed into the consuming module's namespace.

Yes, this is true. It is called flattening. Although I have to say, I didn't know that is what is done with mix-ins, although my experience with them is limited.

Apart from moving them to deterministic compile-time, how do traits help resolve ordering problems associated with MI?

There is no inheritance to be had, so no diamond problem can occur, this is the benefit of flattening the methods into the consuming class. Of course, I cannot guarantee that someone could not figure out a way in which MI problems might creep in, and therefore break Traits. But to the best of my knowledge, they avoid the issues of MI, by avoiding inheritance in general.

Also, when multiple traits are added into a class, they are first combined into a composite trait. The rules for combining traits are described best in the paper "Traits - A Formal Model", which can be found on this page, a lesser description can be had in Re: Traits as Method Exporters, which I linked to above. The rules are grounded in set-theory and other mathematical esoteria of which I only know a limited amount about. The point is that you don't have the same rules when combining traits as you do when you combine classes with MI, and no more than one trait is ever combined into a class.

Do you simply get compiler errors when redefining subs/interfaces?

When you redefine them where? When combining Traits into a composite trait, method conflicts result in the exclusion of both methods, and that method's label is then added to the requirements list.

The idea here is that you should manually resolve conflict up front with the exclude and alias options, and if one were to creep in unexpectedly, Traits make no claims to know what you meant to do, and so defer it back to you. The result is that when your class uses your trait, and does not fulfill the new requirement (created from the method conflict in the the composite trait) your compiler goes BOOM.

As for the method conflict in a class and a trait, Ovid actually explains that. Remember Traits are not classes, and traits are subservient to classes.

What means does the programmer have to resolve these conflicts? (I saw something called "aliases", but if that's a proposed solution to the problem then I'm not sure how it works;

Aliasing allows you to rename a method, which can avoid a conflict since conflicts are checked based on method label (and if labels match, we also check to see if the code reference is the same too before deciding it is truly in conflict). Aliasing simply changes the label, nothing more, nothing less.

I thought the strength of interfaces was that foreign code knows precisely which method to call and can assume that method fulfills a particular interface.
Again, traits are not interfaces, and they have no contract outside of their relationship with the class that uses them.

Also, an implementation question. Suppose I have class Base that uses traits. Then along comes class Child. Where does it get its traits from?

It doesn't get them from anywhere (as Ovid says). The fact Base uses traits, is not known to the Child. Its is Base's concern only, as far as Child can tell, Base implemented its methods on its own.

what should happen when Child consumes another trait of its own, that conflicts with something from Base.

It won't conflict, at least not in the way I think you are thinking it will conflict. As far as Child knows, Base implemented its own methods. Any traits which Child uses are mostly unconcerned with Base. However, there are subtleties to this. If you are interested look at the test file "50_Trait_SUPER_test.t", which uses t/test_lib/Read.pm , t/test_lib/SyncRead.pm and t/test_lib/TSyncRead.pm. It is an implementation of an example given the papers about how Traits deal with and relate to the super class of the class that uses them.

Hope this helps your understanding of traits :)

-stvn

In reply to Re^3: interface.pm explained by stvn
in thread interface.pm explained by gaal

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (6)
As of 2024-04-25 22:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found