list of dots University of Ottawa logo / Université d'Ottawa

User Manual    [Previous]   [Next]   

Required Interfaces of Traits

A required interface is an interface that a trait declares that it (or its clients) implement using the isA clause. A required interface groups together several required methods. The following two paragraphs explain this in more depth.

Required functionality of classic traits is defined in terms of required methods. However, there are shortcomings to just listing the required methods. The first shortcoming is that there is no way to reuse a list of required methods. For example, consider a case in which there are several traits that happen to have the same set of required methods but different provided methods. In this case, there is duplication due to repeated listing of the same methods. Furthermore, if there are several traits that must always have the same list of required methods, an inconsistency could be introduced in the design by changing just one of them and not all.

A required interface also allows putting a restriction on a trait's clients that specifies the interfaces they must implement. Such a restriction ensures that traits are not used in clients that just happen to have methods with the same signature.

So using required interfaces, traits can either put extra restrictions on clients (i.e. interfaces the clients must implement) or just manage their required methods in a more modular and reusable way. Traits may use already-existing interfaces or new interfaces may be written to accomplish the desired modularization. Furthermore, developers can create a hierarchy of interfaces to optimize the reusability.

Traits define their required interfaces through the keyword 'isA' followed by the name of interfaces and a semi-colon. When a class uses traits, it needs to implement the required interfaces of those traits. If a trait uses other traits with required interfaces, those required interfaces are added to the set of required interfaces of the trait, and final clients are required to implement all of those required interfaces.

The example 1 below shows how required interfaces are used and applied. There is a hierarchical design for required methods in terms of interfaces, making it reusable and consistent. Traits T1 and T2 have the same required interface (lines 14 and 18) and if there is a modification in the required interface it will be applied to both. Classes C1 and C2 have to implement interfaces I1 (Line 29) and I2 (line 32) to be able to use trait T1 and T2.


When exploring the following example in UmpleOnline, you can use the Options menu to control what is visible, or you can use control-R to flip back and forth between showing the diagram with the original traits, vs. the diagram collapsed into the classes to be compiled; or you can use control-M to show/hide methods.


  Example 1: showing how required interfaces
  in traits are defined and used.
  To see different diagram views in UmpleOnline:
    Use control-g for auto-layout
      (if not already showing)
    Use control-r to switch between trait view and
       plain classes resulting from applying traits
    Use control-m to show/hide methods
interface I1{
  void method1();
  double method2();
interface I2 {
  isA I1;
  Boolean method3();
trait T1{
  isA I1;
  Float method3(){/*implementation*/ }	
trait T2{
  isA I1;
  Float method4(){/*implementation*/ }	
trait T3{
  isA T1,T2;
class C3{
  void method1(){/*implementation*/ }
  Double method2(){/*implementation*/ }
class C1{
  isA C3, I1, T1;
class C2 {
  isA C3, I2, T3;
  Boolean method3(){/*implementation*/ }
// @@@skipcompile Java code not compilable

Load the above code into UmpleOnline