Generics

Gosu supports Java-style Generics, but the rules are slightly different:

Using Generics

You use generics just like you do in Java:

       
  var lst = new java.util.List<String>()
  lst.add("A String")
  for( s in lst ) {
   print( '"${s}" has length ${s.length}')
  }
     
Everything is statically typed and, thus, can support code completion.

When I say type parameters are covariant, what I mean is that this code works:

      
 var lst = new java.util.List<String>()
 lst.add("A String")
 var lstOfObjs : List<Object> = lst // This assignment is allowed, since String is assignable to Object
    
Technically, this is unsound, because you could do this:
      
  lstOfObjs.add( 11 ) // oops
    
However, this is not a common error, as evidenced by the fact that Java was able to be a perfectly productive programming language for many years with untyped collections, and by the fact that so many people are productive in dynamically typed languages.

An advantage of this approach to Generics is that Gosu can have a properly typed List.contains() method as well:

      
 var lst = new java.util.List<String>()
 lst.contains( 10 ) // compilation error in Gosu, unlike Java and Scala
    
It turns out that (as of this writing) both Java and Scala can't properly type contains() due to their generics systems.

Covariant Generics will not please people who enjoy type theory or who feel that a type system is there to catch every possible error, but, in our experience, this approach gives you the biggest bang for your buck when writing practical software.

Generic Classes

You declare type variables just like you do in Java:

       
  package example
  
  class MyGenericClass<T> {
    var _tee : T as readonly Tee
    
    construct( tee : T ) {
      _tee = tee
    }
  }
     

You can constrain type variables just like you do in Java:

        
   package example

   class MyGenericClass<T extends Runnable> {
     var _tee : T as readonly Tee

     construct( tee : T ) {
       _tee = tee
     }
   }
      

You can refer to type variables as expressions:

        
  package example
  
  uses gw.lang.reflect.IType
  
  class MyGenericClass<T> {
    var _tee : T as readonly Tee

    construct( tee : T ) {
      _tee = tee
    }
    
    property get TeeType : IType {
      return T
    }
  }
      

You can also declare generic functions:

        
  package example

  class MyGenericClass<T> {
    var _tee : T as readonly Tee

    construct( tee : T ) {
      _tee = tee
    }
    
    static function create<T2>( val : T2 ) : MyGenericClass<T2> {
      return new MyGenericClass<T2>( val )
    }
  }  
      
which are invoked as you would expect:
        
  var x = MyGenericClass.create<String>("A String")
      
Of course, you can just let type inference do its thing as well:

        
  var x = MyGenericClass.create("A String") // Still typed as MyGenericClass<String> thanks to type inference
      

Reification

Gosu makes a best effort to reify type variables. The rules are: Practically, the distinction between statically and dynamically reified type variables rarely matters, but it is something to keep in mind.