Enhancements

Enhancements provide a way to add methods and properties to existing types. They are similar to Extension Methods in C#, but do not need to be explicitly imported.

Syntax

Enhancements must be defined in files ending in the .gsx suffix. They cannot be defined inline within other gosu resources presently.

Here is an example enhancement that adds a method to java.lang.String:

        
  package example
  
  enhancement MyStringEnhancement : String {
    function printMe() {
      print( this )
    }
  }
      
In enhancements, the this symbol refers to the enhanced type, rather than the enhancement.

Given the enhancement above, you can invoke the printMe() method on Strings like this:

        
  "Hello Enhancements".printMe()
      

Semantics And Limitations

The above code can be thought of as shorthand for this code:
        
  example.MyStringEnhancement.print( "Hello World" )
      
Enhancements are statically dispatched. This means they cannot be used to implement interfaces or to achieve polymorphism (unless you use a filthy, awful hack.)

We informally refer to using enhancements as "donkey patching" a class. They are kind of like a monkey patch, but a bit more formalized. Only a bit.

Generics

Enhancements can be generic, so you can add an enhancement to List<T>:
        
  package example
  
  uses java.util.List
  
  enhancement MyListEnhancement<T> : List<T> {
    function firstAndLast() : List<T> {
      return {this.first(), this.last()}
    }
  }
      
This method will now be available on all generic lists, and will be properly typed.

Type Variable Reification

Unlike in Java, type variables can be used in general expressions in Gosu. In Enhancements, the type variables are statically, rather than dynamically, reified, much like enhancement methods are statically, rather than dynamically dispatched. The enhancement method toTypedArray():T[] on Iterable<T> demonstrates this:

        
  var lstOfStrings : List<String> = {"a", "b", "c"}
  var arrOfStrings = lstOfStrings.toTypedArray() //returns a String[]
  
  var lstOfObjs : List<Object> = lstOfStrings //type variables are covariant in Gosu, see generics        
  var arrOfObjs = lstOfObjs.toTypedArray() //returns an Object[]
      
This "best effort" reification usually does what you want, but can occasionally lead to surprising results.

Enhancing Parameterized Types

A really neat trick with enhancements is that you can enhance parameterized types:

        
  package example
  
  uses java.util.*
  
  enhancement MyListOfDatesEnhancement : List<Date> {
    function allBetween( start : Date, end : Date ) : List<Date>{
      var lst = new ArrayList<Date>()
      for( d in this ) {
        if( start <= d and d <= end ) {
          lst.add( d )          
        }
      }
      return lst 
      // NOTE: you would normally write this using blocks:
      //  return this.where( \ d -> start <= d and d <= end )
    }
  }
      
This is how all lists of comparable objects have the sort() method on them, while other lists do not.

Sweet.