Restricting generics
You can use restrictions on generics to define a parameter that supports a specific set of types. For example, you might want to support homogeneous collections or only instances of a class and its subclasses or subinterfaces. A homogeneous collection is one in which all items are of the same type.
Consider a custom class Shape. You might need a method to support collections of circle shapes
or collections of line shapes, where both Circle and Line classes extend the
Shape class. For this example, assume the collections are always homogeneous and never
contain a mix of both types. You might attempt to define a method like this:
public function DrawMe(shapeArray : ArrayList<Shape>)
The method accepts an argument of only type ArrayList<Shape>. Your code would not compile
if you tried to pass an ArrayList<Circle> to the method, even though
Circle is a subclass of Shape.
You can specify support of multiple types but limit support to certain types and types that
extend those types. Use the syntax extends TYPE after the
type wildcard character. In Java, this restriction is known as bounded
generics.
For example:
public function DrawMe(shapeArray : ArrayList<T extends Shape>)
A valid argument for the parameter shapeArray is an ArrayList containing
objects that are all of the same type, and that type extends the Shape class.
Example: Generic class using a restricted bound for its type parameter
The following class restricts the generic type to types that extend
Number:
class BoundedGenericsTest<T extends Number> {
// Print out (for debugging) and then return the first item in the list, strongly typed
public function printAndReturnFirst(aList : ArrayList<T>) : T {
print(aList[0])
return aList[0]
}
}The
following sections use this class in code examples.Instantiating a generic class that is restricted
Instantiating a generic class that is restricted is very similar to instantiating a generic class that is not restricted. The only difference is that if you specify a type parameter for the type token, the restriction must apply to that type.
- Using the type token for the type parameter requires information about the type at run
time. If you instantiate a generic class in this way in a parameterized method, you must
use the
reifiedkeyword in the method declaration. This instantiation creates a strongly typed object that uses the explicit type that is reified by the method. For example, in the following lines of code, the type of the variable x isBoundedGenericsTest<T>where T is the type of the method parametert:public reified function makeANewGenericOfSpecifiedType<T extends Integer>(t : T) { var x = new BoundedGenericsTest<T>() } - Specifying the type of the type parameter creates a strongly typed object that uses
the explicit type. For example, in the following line of code, the type of the variable
x is
BoundedGenericsTest<Integer>:public function makeANewGenericOfSpecificType() { var x = new BoundedGenericsTest<Integer>() }You can include this instantiation of
BoundedGenericsTestin a parameterized method without using thereifiedkeyword because you have provided Gosu with the necessary information for the type parameter. - Omitting the type parameter creates a strongly typed object that uses the least
restrictive type of the bound. For example, in the following line of code, the type of
the variable x is
BoundedGenericsTest<Number>:public function makeANewGenericOfNonspecificType() { var x = new BoundedGenericsTest() }You can include this instantiation of
BoundedGenericsTestin a parameterized method without using thereifiedkeyword because Gosu substitutes the least restrictive type of the specified bound for the type parameter.
See also
Arithmetic operations on type parameter restricted to Number
types
Number. You must use casting if you need to
perform these operations. For example, the following code does not
compile:function doArithmetic<T extends java.lang.Number>(d1 : double, d2 : T) : T {
var result = d1 + d2
return result
}function doArithmetic(d1 : double, d2 : T) : T {
var d3 = d2 as Double
var result = d1 + d3
return result as T
}As always for code that uses casting, you must be certain that the values you use can be cast in this way at run time.
Restricting parameterized enhancements of classes
If you create an enhancement of a parameterized class that applies to a restricted set of types, you must use the correct syntax. For example, consider a parameterized class, GenericsTest that has the following declaration:
class GenericsTest<T>
For an enhancement that applies to a restricted set of type on the generic class, you
specify the restrictions on the enhancement name and the type wildcard character on the
class name. For example, the declaration of an enhancement to types that extend
CharSequence types of the GenericsTest class looks
like the following line:
enhancement GenericsTest_CharSeqEnh<T extends CharSequence> : GenericsTest<T>
See also
