Here's a miscellany of other Gosu features you might find useful:
You can set properties of an object after it's constructor by using the object initializer syntax:
var newObj = new MyClass() { :Prop1 = "Foo", :Prop2 = "Bar" }This will construct the
MyClass
object and then set the Prop1
and
Prop2
properties to the given values. This syntax is often useful when declaring "declarative"-like data, such as test or configuration data.
Gosu programs can embed a classpath in their source, obviating the need for users to pass in a correct classpath externally:
#! /path/to/gosu classpath "../src,../lib/sweet_lib1.jar" print( "Here is a sweet library object: ${new SweetLibraryObject()}")The classpath statement is comma delimited, to avoid system specific dependencies. Each path on it will be added to the classpath. If a path points at a folder and that folder contains jars, all those jars will be added to the classpath as well.
This makes it much more pleasant to run gosu programs on *nix:
Thumper carson$ ./my_sweet_gosu_program.gsp Here is a sweet library object: super.SweetLibraryObject@12b27c3No wrapping scripts, no complicated class paths.
Rather than writing code like this:
var conn = getConnection() try { conn.execute( "Some advanced SQL" ) } finally { conn.close() }You can use the using statement:
using( var conn = getConnection() ) { conn.execute( "Some advanced SQL" ) }The using statement will automatically clean up the resource for you.
Gosu supports named arguments if two conditions are met:
function printIt( msg:String, escapeIt:boolean, printDate:boolean) { if( escapeIt ) { msg = msg.replace( "<", "<" ) } if( printDate ) { msg = (new Date()) + " " + msg } print( msg ) } printIt( "<b>Hello World</b>", true, true ) // what does that mean? printIt( :msg = "<b>Hello World</b>", :escapeIt = true, :printDate = true ) // Oh.When methods take lots of arguments, or lots of non-descript arguments like booleans, named arguments can help clarify your code dramatically.
Named arguments can also be combined with default parameters, discussed next, to make for great APIs.
Gosu supports default parameter values. The printIt
method could be rewritten like so:
function printIt( msg:String, escapeIt:boolean = true, printDate:boolean = true) { if( escapeIt ) { msg = msg.replace( "<", "<" ) } if( printDate ) { msg = (new Date()) + " " + msg } print( msg ) } printIt( "<b>Hello World</b>" ) // I'm happy with the defaults...API designers take note: no need for telescoping methods in Gosu!
Sometimes you want to refer to a method on a Class. Gosu lets you do that like this:
var mr = String#substring(int)You can then invoke the Method Reference like so:
print( mr.invoke( "A String", 2 ) ) // the same as "A String".substring( 2 )You can also bind a Method Reference to an instance:
var mr = "A String"#substring(int) print( mr.invoke( 2 ) ) // same as aboveAs well as to parameters: You can also bind a Method Reference to an instance:
var mr = "A String"#substring(2) print( mr.invoke() ) // same as aboveGiven a Method Reference, you can convert it to a block like so:
var blk = mr.toBlock()And you can get to the MethodInfo (The Gosu Type System equivalent of
java.lang.reflect.Method
) like so:
var blk = mr.MethodInfo
There are equivalent references for Properties and Constructors
Finally, you can refer to feature chains:
var methodChain = String#substring(int)#toUpperCase()Feature chains are probably most useful when combined with properties, for things like UI-binding layers:
var binding = aContact#Address#ZipCode var widget = new Widget(binding)This (hypothetical) UI framework would then use the binding to get and set the value of the
ZipCode
field associated with the instance aContact.Address
.
Gosu supports a range operator:
var zeroToTenInclusive = 0..10 var zeroToTenExclusiveOfTen = 0..|10 var zeroToTenExclusiveOfZeroAndTen = 0|..|10 for( i in zeroToTenInclusive ) { print( "i is ${i}" ) }The range operator works with numeric types and dates, as well as anything implementing
gw.lang.reflect.interval.ISequenceable
Gosu supports usage of Java annotations:
@java.lang.Deprecated function oldCrustyMethod() : String { return "bah" }
Gosu also supports its own version of annotation declarations: implement gw.lang.IAnnotation
and you are
an annotation.
Annotations declared like this can be used the same way as Java-style annotations.
If you have an Gosu-style annotation that implements gw.lang.reflect.IMethodCallValidator
, you can put
that annotation on a feature and the annotation will be invoked at compile time. This allows you to plug in
to the compiler and give additional feedback or put additional constraints on how a method is used.
For example, you might want to insist that your method only takes literals.
This API is very much in flux, but also pretty awesome.
This is a "feature" noticed by Alan Keefer: if you create an Interface and then create an Enhancement on that interface, you've effectively created a Mixin: anyone who implements that interface gets all the enhancement functionality mixed in.