Mixins in JavaFX 1.2 Technology

By Robert Eckstein, August 2009

With the release of version 1.2 of JavaFX technology, developers have a new style of class inheritance: a mixin. A mixin is a type of class that can be inherited by a subclass, but it is not meant for instantiation. In this manner, mixins are similar to interfaces in the Java programming language. However, the difference is that mixins may actually define method bodies and class variables in addition to constants and method signatures.

Let's look at an example that compares Java technology with JavaFX technology. In the Java programming language, you can create an interface that mandates that any implementing class must define methods that match the stated signatures.

The benefit with JavaFX technology is that if you have functions or variables that are duplicated across multiple classes, you can maintain them in a single file in JavaFX, as opposed to maintaining them in each class that implements the interface in Java technology.

Multiple Inheritance and the Diamond Problem

With version 1.2, JavaFX no longer directly supports multiple inheritance. Instead, the language incorporates various features that act as a middle ground, with the aim to offer many of the benefits of multiple inheritance while avoiding the implementation complexities. To demonstrate such a complexity, let's talk about one of the most common pitfalls of multiple inheritance: an ambiguity that language designers often call the diamond problem.

The textbook definition of the diamond problem often outlines two classes, ClassB and ClassC, that extend (or inherit from) ClassA. The definition also outlines ClassD, which extends both ClassB and ClassC. Figure 1 shows this relationship.

Figure 1: The Diamond Problem

Note that ClassA has an abstract method called myMethod(), and that ClassB and ClassC provide two different implementations of that method. ClassD has the whichOne() method, which invokes the myFunction() method.

However, this brings to light an ambiguity: If the whichOne() method is called in ClassD, which version of myMethod() gets invoked: the version in ClassB or the version in ClassC?

The diamond problem is intentionally simplistic, but the ambiguities that such a scenario creates can demonstrate how problematic the implementation of multiple-inheritance language runtimes can become.

For this and other reasons, the designers of the JavaFX language decided to strip pure multiple inheritance out of version 1.2. According to the designers, removal of multiple inheritance would simplify the language, eliminate many bugs, and make the generated "code simpler, smaller, and faster, because all classes [had been] burdened with the machinery of multiple inheritance even though few classes used them. In reality, [JavaFX] code will not change very much. Most of the uses of multiple inheritance that we've found are handled perfectly well by mixins, and for those, simply adding the 'mixin' keyword in front of classes that are designed for multiple inheritance will do the trick."

Mixin Specifics

Now that you have an understanding of how mixins work, let's look at the specifics. The new inheritance rules for JavaFX technology are more formally stated in the official documentation:

JavaFX classes are allowed to extend, at most, one other JavaFX class. Because the JavaFX Script programming language is based on the Java platform, this superclass also could be written in Java and your code would still compile and run correctly.

JavaFX classes are allowed to extend any number of JavaFX mixin classes — this offers a degree of multiple inheritance in the JavaFX language. (If you are a Java programmer, know that JavaFX classes can also extend any number of Java interfaces as well.)

JavaFX mixin classes are allowed to extend any number of other JavaFX mixin classes. As with #2 above, JavaFX mixin classes may also extend any number of Java interfaces. Note that "When a class includes a mixin, the class … includes, rather than inherits, all the mixin's attributes and methods. They become part of the class during compilation."

You may have noticed that because mixins offer multiple inheritance, you can again encounter the diamond problem, but many of these issues can be resolved at compile-time. With JavaFX technology, you can get around this by qualifying the function that you intend to invoke. Consider the following example:

Here, the myFunction() method in class C disambiguates the foo() method calls by specifying the parent that you intend to invoke. It would be legal to call both B.foo() and M.foo(). However, as you might expect, you can invoke only functions that are direct parents or superclasses. You can't invoke A.foo() because A is not a direct superclass or parent mixin.

The diamond problem specified earlier is a simplified version of a common multiple-inheritance issue. In practice, class hierarchies can consist of hundreds of classes with a wide variety of structures. As such, it is possible for the same variable or function to be declared in multiple parent mixins, or in a mixin and a superclass. If that occurs, the following rules apply for precedence in inheritance:

Superclass variables or functions take precedence over mixin variables or functions.

A mixin declared earlier in the extends list takes precedence over mixins declared later in the extends list.

Also, you can use the this keyword within a mixin function just as you do within abstract classes in the Java programming language. In this case, this refers to the live object on which the method has been invoked.

Variables in mixins are treated in much the same way as functions. As with JavaFX classes, a variable declaration includes the variable name, the variable type, and optionally a default value and on replace triggers. If the inheriting class does not override a mixin variable, it inherits that mixin variable and any default values that are defined. For example, consider the following example, provided by Brian Goetz:

In this example, classes A, B, and C each extend — directly or indirectly — mixin M. Class A does not provide its own declaration for the variable x, so the declaration and default value are inherited from mixin class M.

B overrides M with its own declaration and default value. Note that there is no need to specify the variable type again, because the compiler already knows that x is an Integer. If you specify the variable type at this point, the JavaFX compiler will flag it as an error.

C inherits the declaration and default value from B. Note that when inheriting a variable from a mixin class, the class can use the override keyword to either change the default value or add an on replace trigger, or both. In the previous example, class B used the override keyword to set its own default for x.

A variable declaration in a mixin class can contain an on replace trigger. Just as with ordinary classes, this trigger is executed when the value of the variable changes, even if an inheriting class or mixin has declared its own trigger on that variable with an override declaration. In that case, both triggers are executed. Consider this amended example:

When you execute this code, you will see the following output. This demonstrates that the triggers in both B and M are executed, first when the x variable is set to 3, and then again when it is reset to 5.

on replace M
on replace B
on replace M
on replace B

Conclusion

Mixins are an exciting new feature that are new to JavaFX in version 1.2. At this point, you should know how to take advantage of mixins within your JavaFX programs, and be able to author programs that master the complexities of multiple inheritance.

For More Information

Rate This Article

Discussion

We welcome your participation in our community. Please keep your comments civil and on point. You can optionally provide your email address to be notified of repliesyour information is not used for any other purpose. By submitting a comment, you agree to these Terms of Use.