Using generics with collections and blocks
Common uses of generics apply them to collections and to block functions. You can combine these uses of generics to create API methods that are relevant for many purposes. Blocks are anonymous functions that can be passed as parameter objects to other methods.
If a method takes a block as a parameter, you can use generics to describe the set of blocks that the method
supports. The parameter definition specifies the number of arguments, the argument types, and the return type of
the block. For example, consider a block that takes a String parameter and returns another
String. The definition of the block itself indicates one argument, the parameter type
String, and the return type String. In the definition of the block parameter
on the method, you can use generics to specify how the parameter to the block and its return type match the type
on the parameterized class.
For example, Gosu provides an enhancement to the Java List class that provides
additional functionality to any collection. This enhancement provides multiple methods that rely on generics to
determine the type of the collection. A typical example of this use of generics is the list enhancement method
sortBy, which takes a block parameter. That block takes exactly one argument, which must be
the same type as the items in the list. For example, if the list type is ArrayList<String>,
the block must take a String parameter. The following code shows the method definition in the
enhancement.
enhancement CoreListEnhancement<T> : List<T> {
...
function sortBy( value(elt : T):Comparable, comparator : Comparator = null) : List<T>
{
...
}
}
In the definition of the enhancement, the method, and the block parameter, the symbol T is
treated as the type of the collection. Note the use of the letter T in the block signature:
value(elt : T):Comparable
That signature specifies that the block parameter takes one argument of type T and returns a
Comparable value, such as an Integer or String.
Consider the following array list of strings:
var myStrings = new ArrayList<String>(){"a", "abcd", "ab", "abc"}
You can re-sort the list based on the length of the strings by using a block. Create a block that takes a
String parameter and returns the sort key, in this case the text length. The
List.sortBy(...) method implements the sorting algorithm to sort the original list in place,
and does not return an entirely new list.
The following example uses the sortBy method to sort a list of String objects
by the length of the String, and then prints the sorted list values.
var resortedStrings = myStrings.sortBy( \ str -> str.length() )
resortedStrings.each( \ str -> print( str ) )
This code prints:
a
ab
abc
abcd
Using generics for type inference in cases like this example produces readable and concise Gosu code.
This example omitted the types of the block argument str and the sort key. You do not have to
specify these types explicitly. Although the following code is valid, Gosu uses type inference to determine the
types.
var resortedStrings = myStrings.sortBy( \ str : String -> str.length() as Integer )
See also
