Data

Data structures are one of the most important aspects of a language when it comes to productivity. Java has great implementations of the common data structures (e.g java.util.ArrayList and java.util.HashTable) but it doesn't help you much when you want to manipulate them: you often end up writing out the same code over and over again to filter lists, to sort them, etc.

Gosu addresses this problem by adding new methods that leverage Gosu's language features (blocks, in particular) to the core data structures from Java. Gosu also provides additional syntactic support for common collections.

Lists

As you may have noticed, a list in Gosu can be declared by using {}'s:

        
  var lstOfStrings = {"This", "is", "a", "list"}
      
You can use Array-style access on lists:
        
  var lstOfStrings = {"This", "is", "a", "list"}
  print( lstOfStrings[2] ) // prints "a"
      

Blocks

Lists in Gosu have a lot of enhancement methods on them, many of which use blocks. Blocks (also called closures or lambda expressions) are a simple way to specify an inline function. They have a lot of uses, but they really shine in data structure manipulation:

        
  var lstOfStrings = {"This", "is", "a", "list"}
  var longStrings = lstOfStrings.where( \ s -> s.length > 2 )
  print( longStrings.join(", ") )  // prints "This, list"
      
The funny \-> thing is the block. It declares a mini-function that says "Given a String s return whether s.length is greater than two". You can think of it as an inline version of this function:
        
  function isLongerThanTwo( s : String ) : boolean {
    return s.length > 2
  }
      
Or, if you prefer, this anonymous inner class:
            
  var inner = new com.google.common.base.Predicate<String>() {
    function apply( s : String ) : boolean {
      return s.length > 2
    }
  }
      
Blocks allow you to express this logic much more succinctly.

Note that I didn't have to declare a type for the block's parameter, s, like I did in the function and anonymous class above. This because the block is defined in a context where Gosu can figure out the argument is a String. Typically you will not have to define the types of the arguments of blocks.

With blocks you can often remove loads of iterative code you would end up writing in Java. Consider this java code:


  List<String> lstOfStrings = Arrays.asList("This", "is", "a", "list");

  List<String> longStrings = new ArrayList<String>();
  
  for( String s : lstOfStrings ) {
    if( s.length() > 2 ) {
      longStrings.add( s.toUpperCase() );
    }
  }
  
  Collections.sort(longStrings, new Comparator<String>() {
    public int compare( String s, String s2 ) {
      return s.compareTo( s2 );
    }
  })

  StringBuilder sb = new StringBuilder();
  for( String s : longStrings ) {
    if(sb.length() != 0) {
      sb.append(", ");
    }
    sb.append(s);
  }

  System.out.println(sb.toString());
      
This code can be written in Gosu like so:
        
  var lstOfStrings = {"This", "is", "a", "list"}
  var longStrings = lstOfStrings.where( \ s -> s.length > 2 )
                                .map( \ s -> s.toUpperCase() )  // converts each string to upper case
                                .orderBy( \ s -> s )            // there is a .order() method that could be used here instead
  print( longStrings.join(", ") ) // prints "LIST, THIS"
      
In Gosu the code more clearly expressed the algorithm, it is less coupled (there is no mix of algorithmic steps in a for-loop, for example) and certainly less verbose.

Blocks have other uses, but, by and large, the big win with them is in Collection manipulation.

Blocks and Interfaces

Java has many interfaces that contain a single method, which are used as a stand-in for actual closures. In order to facilitate Java interoperability, Gosu blocks and one-method interfaces are automatically converted between one another:

        
  var r : Runnable
  r = \-> print("This block was converted to a Runnable")
      
This makes some Java APIs very enjoyable to work with in Gosu.

List Enhancements

Here are some of the more useful enhancement methods on Lists:

There are more. Code completion is your friend.

Maps

Maps can be declared by using {}'s with a right-arrow between keys and values:

        
  var mapOfStringsToStrings = {"This" -> "is", "a" -> "map"}
      
You can also use Array-style access on maps:
        
  var mapOfStringsToStrings = {"This" -> "is", "a" -> "map"}
  print( mapOfStringsToStrings["This"] ) // prints "is"
      

Map Enhancements

There are fewer enhancement methods on Maps than Lists, but there are some:

One useful trick is to use methods on Map.entrySet() to modify the Map:
        
  var mapOfStringsToStrings = {"This" -> "is", "a" -> "map"}
  // removes all entries with a key whose length is less than 2
  mapOfStringsToStrings.entrySet().retainWhere( \ p -> p.Key.length > 2  )