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.
public interface MyInterface {
public void myFunction(Object param1);
}
public class MyClass1 implements MyInterface {
public String variable1 = "Hello";
public String variable2 = "World";
public void myFunction(Object param1) {
System.out.println("Java says: " + variable1 + " " +
variable2);
}
}
public class MyClass2 implements MyInterface {
public String variable1 = "Hello";
public String variable2 = "World";
public void myFunction(Object param1) {
System.out.println("Java says: " + variable1 + " " +
variable2);
}
}
Note that in this example, the body of the Now compare a mixin that accomplishes something similar in JavaFX technology:
mixin class MyMixin {
var variable1 = "Hello";
var variable2 = "World";
function myFunction():Void {
println("JavaFX says: {variable1} {variable2}");
}
}
class MyClass1 extends MyMixin { }
class MyClass2 extends MyMixin { }
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 ProblemWith 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, ![]() Figure 1: The Diamond Problem
Note that However, this brings to light an ambiguity: If the 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 SpecificsNow 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:
You should be aware of a few other rules, as initially provided by designer Brian Goetz in a posting on the JavaFX forums and expanded here. As this article mentioned earlier, you cannot instantiate a mixin. In other words, you cannot do the following: var m:MyMixin = new MyMixin(); // ILLEGAL. COMPILER ERROR. In addition, you cannot instantiate a mixin using the alternative JavaFX object-literal form:
var m:MyMixin = MyMixin { // ILLEGAL. COMPILER ERROR.
variable1: "Hello Again"
variable2: "World"
}
Instead, you can only instantiate a class that extends the mixin class. var c:MyClass1 = new MyClass1(); // CORRECT Just like the abstract classes and interfaces in Java technology, the JavaFX compiler treats a mixin class as a named type. As such, it is valid to do both of the following:
var myClass1Instance = new MyClass1();
var m:MyMixin = myClass1Instance; // CORRECT
if (myClass1Instance instanceof MyMixin) { // CORRECT
println("true");
}
As this article mentioned earlier, a function declaration inside a mixin may have a body. Alternatively, it may be declared abstract if a subclass must provide an implementing function.
mixin class MyMixin {
function myFunction1():Void { // CORRECT: FUNCTION HAS BODY
println("Hello World");
}
abstract function myFunction2():Void; // NO BODY, IS ABSTRACT
}
class MyClass1 extends MyMixin {
override function myFunction1():Void {
// CORRECT. (IF ABSENT, USES DEFAULT VERSION IN MyMixin)
}
override function myFunction2():Void {
// REQUIRED BECAUSE THE MyMixin FUNCTION IS ABSTRACT
}
}
Mixins may extend one ore more other mixins. Note that if a mixin function is itself inheriting from a parent mixin, the keyword
mixin class MyMixin1 {
abstract function myFunction():Void;
}
mixin class MyMixin2 extends MyMixin1 {
override function myFunction():Void {
// MUST USE OVERRIDE KEYWORD BECAUSE MyMixin2 EXTENDS MyMixin1
}
}
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:
mixin class M {
public function foo() : Void {
println("M foo");
}
}
class B {
public function foo() : Void {
println("B foo");
}
}
class A extends B {
override public function foo() : Void {
println("A foo");
}
}
class C extends B, M {
public function myFunction() : Void {
B.foo(); // LEGAL
M.foo(); // LEGAL
A.foo(); // ILLEGAL: Not direct superclass or parent
}
}
Here, the 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:
Also, you can use the
mixin class MyMixin {
var variable1 = "Hello";
var variable2 = "World";
function myFunction():Void {
println("This object is: {this}");
}
}
class MyClass1 extends MyMixin { }
class MyClass2 extends MyMixin { }
var m1:MyClass1 = new MyClass1();
m1.myFunction(); // Prints the MyClass1 object reference
var m2:MyClass2 = new MyClass2();
m2.myFunction(); // Prints the MyClass2 object reference
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
mixin class M {
public var x : Integer = 0;
public function getX() : Integer { x }
}
class A extends M { }
class B extends M {
override public var x = 3;
}
class C extends B { }
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 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 C inherits the declaration and default value from B. Note that when inheriting a variable from a mixin class, the class can use the A variable declaration in a mixin class can contain an
mixin class M {
public var x : Integer = 0 on replace {
println("on replace M");
}
public function getX() : Integer { x }
}
class A extends M { }
class B extends M {
override public var x = 3 on replace {
println("on replace B");
}
}
class C extends B { }
var c:C = new C();
c.x = 5;
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 on replace M on replace B on replace M on replace B ConclusionMixins 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
JavaFX Home Page Rate This ArticleDiscussionWe 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 repliesyour information is not used for any other purpose. By submitting a comment, you agree to these Terms of Use. |
Robert Eckstein has worked with Java technology since its first release. Formerly a programmer and editor for O'Reilly Media, Inc., and a programmer for Motorola's cellular technology division, he is now a senior staff writer on java.sun.com.
| |||||||
|
| ||||||||||||