Jump to content

Traits - An alternative to interfaces, mixins, etc.


Recommended Posts

Recently I ran across a paper describing Traits as an alternative and superior construct to handle code reuse. From what I understand they are similar to Interfaces except they allow (but do not require) the Trait to implement the methods it defines. Classes can be built by composing the traits containing the functionality you want the class to have, thus avoiding the inheritance problems associated with multiple inheritance and mixins.

I'd love to see traits implemented in G. I think it would something of a cross between an lvlib and lvclass, with a bit of it's own features built on top. I'm pretty sure you can manually build the code structure traits encourage, but having an .lvtrait construct would make it so much easier.

Thoughts?

[Edit - Posted to Idea Exchange]

Link to comment

Interesting indeed. I like the idea how you can define both an interface and implementation- not too different from virtual classes- but it is all stateless at the trait level. The paradigm shift would seem to be the "glue" as they call it: how a class essentially becomes a means of connecting the state to the trait(s). Also like how the class becomes focused on state creation (instantiation), whereas the traits become the main means of defining behaviors/interface.

Having not thought about it too much, I do question though if inheritance is even required in a system which allows traits.

Link to comment

The .lvtrait library would presumably be able to be owned simultaneously by multiple .lvclass libraries.

No, I don't think that would be necessary. Classes could be composed with traits, but the trait isn't owned by the class. I envision it would be similar to how a class can be a member of another class, but the first class isn't "owned" by the second class. They're still two separate entities. Using LV's current paradigm a trait would need a fp representation (similar to a class) so it could be put in a class, but since they are stateless (like a library) there wouldn't be a .ctl or wire associated with it.

I like the idea how you can define both an interface and implementation- not too different from virtual classes- but it is all stateless at the trait level.

Yeah, and it seems to be a more natural fit for Labview than Interfaces or virtual classes.

The paradigm shift would seem to be the "glue" as they call it: how a class essentially becomes a means of connecting the state to the trait(s). Also like how the class becomes focused on state creation (instantiation), whereas the traits become the main means of defining behaviors/interface.

I have to confess I do have a bit of an ulterior motive to posting this paper. Traits as implemented in the paper closely align with how I prefer to build code--small units of reusable code with focused fuctionality that are composed into larger units (classes) based on the needs of the application. One of the biggest problems I face is creating applications with a lot of composition means there's a lot of delegation. Delegation methods are boring to write and I've had several people complain it's too confusing. Traits could be a partial solution to that issue.

Some of the details still escape me though... For example, a trait provides a set of methods that implement a behavior and requires a set of methods the class (or another trait, or perhaps a child class?) needs to implement. (page 7) Can these methods be overridden in child classes? My guess is provided methods cannot be overridden but required methods can. I'd like to play around with a language that implements them and see how they work.

Having not thought about it too much, I do question though if inheritance is even required in a system which allows traits.

Yes, absolutely. I don't expect all the class' behaviors are defined by traits. In addition to overriding a required method, there will still be times when you'd want to derive a child class to change behavior (such as creating test doubles) or to add new methods.

Link to comment
Some of the details still escape me though... For example, a trait provides a set of methods that implement a behavior and requires a set of methods the class (or another trait, or perhaps a child class?) needs to implement. (page 7) Can these methods be overridden in child classes? My guess is provided methods cannot be overridden but required methods can.

From reading the paper, I believe provided methods can be overridden; in fact they sometimes have to be, when there is a "conflict" between identically names methods provided by multiple traits (section 3.5, page 11).

-- James

Link to comment

Some of the details still escape me though... For example, a trait provides a set of methods that implement a behavior and requires a set of methods the class (or another trait, or perhaps a child class?) needs to implement. (page 7) Can these methods be overridden in child classes? My guess is provided methods cannot be overridden but required methods can. I'd like to play around with a language that implements them and see how they work.

From reading the paper, I believe provided methods can be overridden; in fact they sometimes have to be, when there is a "conflict" between identically names methods provided by multiple traits (section 3.5, page 11).

My understanding is that's where the "glue" comes in. Two traits might both require a method ReadCenter, but it's the class that decides what concrete method actually provides that interface, to the point where either trait's interface could map to a different implementations. If I read correctly, the implementation doesn't even need to be named ReadCenter, it could be anything: when composing a class of a trait, the class defines what methods implement the required methods of that trait.

In my mind picturing function pointers in C++, but in LabVIEW land this would be the same as defining a connector pane for ReadCenter. The job then of the class, is to map which member VI (with the same connector pane) of the composing class implements the interface, but because a class might be a composition of multiple traits, the method need not be named ReadCenter. Note the implementing method might even have been introduced via another trait, but since traits likely won't know about one another, it is still the responsibility of the class to provide that glue and either implicitly or explicitly map out the relationship between implementation and interface.

With regards to overriding implementations which are provided by a trait, don't forget there are also precedence rules, a method defined in the class proper always takes precedence over an implementation defined by the trait (if I recall?).

Aliasing is a related topic that I found interesting, though honestly I find it rather inelegant.

All in, I need to read that paper a second time. There's a lot in there, and it is light on some details, though there are references to check as well.

Link to comment

All in, I need to read that paper a second time.

Heh, I'm thinking I need at least a half dozen rereads sprinkled with several helpings of Squeak.

Two traits might both require a method ReadCenter, but it's the class that decides what concrete method actually provides that interface, to the point where either trait's interface could map to a different implementations.

I don't think that's right. On page 8 they show code for the trait TDrawing. The refreshOn method is implemented in the trait and uses the required methods bounds and drawOn. A little further down they show a diagram of a Circle class which uses both TDrawing and TCircle.

TDrawing requires bounds and drawOn, but Circle only implements drawOn. Bounds is implemented by TCircle. There's no glue code specifying that in the class body, so I'm guessing the compiler does linking for required methods automatically based on signature (name and connector pane in LV.)

I suppose it's possible that's just the default behavior and we can create alternative links if desired, but I don't see that specified in the paper. The aliasing example on p.13 is dealing with provided methods, not required methods.

In my mind picturing function pointers in C++, but in LabVIEW land this would be the same as defining a connector pane for ReadCenter. The job then of the class, is to map which member VI (with the same connector pane) of the composing class implements the interface, but because a class might be a composition of multiple traits, the method need not be named ReadCenter.

I don't think this works in LV--at least not the way I'd like it to work. If all the trait defined of the required method was a conpane you have a few options:

1. Initialize a trait with vi references to the methods providing the required services. (Can't do that; traits are stateless.)

2. Include the required vi references on the trait's method conpane. (Yuck.)

3. Require the class using the trait to provide a wrapper method. (I don't see much point in this. We can create trait-like stateless classes in Labview and use them in "real" classes via delegation today.)

4. Invent a new trait table where classes record the mapping. (Nooooo... I want to consolodate information, not spread it out more.)

Or... if we just require the class to implement a method with the same name and conpane as the trait's required methods we can avoid all that hassle. I dream of extending my shortcuts idea to traits. Instant functionality. :D

Not that it doesn't have it's own issues. For example, what happens if we compose a class with mutually dependent traits?

- TraitA provides Rock and requires Scissors.

- TraitB provides Scissors and requires Paper.

- TraitC provides Paper and requires Rock.

Calling any one of them enters an infinite loop. I guess you'd have to override eclipse at least one of the trait methods with a class implementation. Working out that kind of issue might be tricky unless we can manually map required trait methods to a class implementation.

How would we go about using a required method in methods the trait provided? Maybe something like a call by reference node, except it has a string input for the required method's name and a class input that tells it where to look for the method?

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.