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@12b27c3
No 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 above
As 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 above
Given 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.