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