Intro
I don't have time to write a book.
You probably don't have time to read a book.
So, how about a quick introduction to Gosu and how to get productive in it, instead?
Gosu is an imperative, statically typed programming language for the JVM. It is designed to be a easy for Java developers to pick up. If falls between Groovy, which is an imperative, dynamically typed language (with optional type annotations) and Scala, which is a functional-ish, statically typed language.
It's nothing like Clojure, which is a Lisp variant and, therefore, insane.
Why?
Why learn Gosu, given all the alternatives out there? Here are three reasons:
- Gosu is an easier transition from Java than other languages. The focus in Gosu is on making things simpler, rather than more complicated, and on extending existing Java functionality, rather than on inventing new concepts or libraries.
- Since Gosu retains static typing, it is possible to provide good modern IDE support. Having an accurate list of methods pop up a developer hits '.' is as important a productivity tool as any language feature.
- Gosu has a technology called the Open Type System. This allows Gosu to integrate non-Gosu resources directly into the language, which makes for some awesome framework support. For example, there is an XSD Type Loader that will inspect XSD files on the classpath and generate types for the Gosu compiler to work with, removing the need for an ugly code generation step. Just drop an XSD in your source tree and, blam, go.
Installing
- Install Java (any version 1.5 or greater)
- Download Gosu from http://gosu-lang.org
- Unzip it
bin directory of the gosu distribution.
Playing
Gosu ships with a small built in editor that you can use to play around with. If you run bin/gosu with no arguments, you should get a window like this:
You can use this to play around with gosu, write simple programs, etc. The editor offers simple code completion and a few other niceties:
Some useful keyboard shortcuts are:
- Ctrl-Space - Complete code
- Ctrl-T - Show type at current position
- Ctrl-W - Expand Selection
- F5 - Run the current program
Programs
Gosu doesn't have the concept of a public static void main(String[] args) method, because that's just crazy. Instead, it has programs, like Ruby or Python, which are bits of Gosu code in a file ending in the .gsp extension.
Here is hello_word.gsp:
print( "Hello World!")
Easy enough, right?
You run this program like so:
Thumper carson$ gosu hello_world.gsp
Hello World!
Thumper carson$
You can use the gw.lang.cli.CommandLineAccess class to get at arguments passed to your Gosu program.
Setting Up A Project
My favored approach right now is to lay out a project like this:
/proj_name
/src - Gosu classes, XSD's, WSDL's, etc.
/lib - 3rd party jars
/bin - Gosu programs
/test - A directory for your tests
build.vark - An Aardvark build file.
Given this layout, you can add the following to the top of your gosu programs in the /bin directory:
classpath "../src,../lib"
This classpath statement will add the src directory and all jars in the lib directory to the classpath when this program is launched, so you can run your project without any crazy command line setup or secondary scripts:
Thumper carson$ gosu bin/my_prog.gsp
Hello Gosu Projects!
The classpath statement is discussed more on the Misc page
Math
Gosu supports the usual math operators, and they work on the major primitive and non-primitive numeric types, such as BigDecimal and BigInteger
Comparisons
Gosu supports the usual comparison operators:
==- Object equality===- Instance equality>, <, etc.- Standard comparison semantics, works withjava.lang.Comparable
Logical Operators
Gosu supports the usual logical operators, and you can use either the english style not, and and or, or the C-style equivalents. I use the english style operators.
Variables and Control Flow
In Gosu, you typically do not need to declare the type of variables:
var x = 10
print( x + x ) // prints 20
Gosu will infer the type of x to be int.
If you want to explicitly type the variable, you put the type annotation after the variable name:
var x : int = 10
print( x + x ) // prints 20
If
The if statement works just like it does in every other sane language:
var x = 10
if( x > 5 ) {
print( "x was greater than 5")
}
For
The for statement is similar to other languages:
var aList = {"a", "b", "c"} // declare a List<String>
for( x in aList ) {
print( x )
}
The for statement works with both arrays and classes that implement java.lang.Iterable. Note that x is explicitly typed to java.lang.String above, via type inference.
Sometimes you want the index of an iteration. You can use this syntax to get it:
var aList = {"a", "b", "c"}
for( x in aList index i ) {
print( i + ":" + x )
}
i will be the zero-based index of the current loop of the iteration.
Sometimes you want the iterator for the loop. You can use this syntax to get it:
var aList = {"a", "b", "c"}
for( x in aList iterator it ) {
it.remove()
}
it can be used to safely remove items, for example.
Note that the for loop is null safe: no NPE occurs if aList is null, rather the loop simply does not execute.
Etc.
Gosu has while, do/while and switch statements, all of which work like you would expect.
Working With Types
Gosu allows you to determine the runtime type of a value with the typeof operator:
var x = "This is a String"
var t = typeof x
print( t.Name ) // prints java.lang.String
It the code above, the type of t is gw.lang.reflect.IType, which is the Gosu Type System's equivalent of java.lang.Class
Gosu has a way to test if an object is an instance of a type, akin to Java's instanceof keyword: typeis. Here is an example:
var x : Object
x = "A String"
if( x typeis String ) {
print( "x is a String with length " + x.length )
}
One interesting thing about the typeis operator is that how it interacts with logical operators and the if statement. In the code above, note that x was not cast to String, but within the if statement the length property on String was used. Gosu automatically downcast x to String after the typeis expression, so no casting was necessary.
Properties
Gosu supports properties, which are a bit like public fields in Java, but they allow you to associate logic with the reading and writing operations. We will cover property definition below, but this is how you access them:
var p = new MyGosuPersonClass()
p.Name = "Joe"
print( "The name of this person is ${p.Name}")
Properties have some interesting and useful characteristics that will become apparent over time (e.g. they are both an rvalue and an lvalue.)
Gosu automatically converts get/set methods in Java classes into properties, so the following Java class:
public class MyJavaPersonClass {
String _name;
public String getName() {
return _name;
}
public void setName( String s ) {
_name = s;
}
}
Can be used like so:
var p = new MyJavaPersonClass()
p.Name = "Joe"
print( "The name of this person is ${p.Name}")
Null Safety
If you wish to make a null-safe call to a method or property, you can prefix the '.' operator with a question mark, '?':
var x : String = null
print( x?.length ) // prints "null"
Classes
Gosu classes are defined with much the same syntax as other programming languages. You can define classes inside a Gosu program, or in a file ending with the .gs extension. Here is a basic class:
uses java.util.List
class SampleClass {
var _names : List<String> // a private class variable, which is a list of Strings
// A public constructor
construct( names : List<String> ) {
_names = names
}
// A public function
function printNames( prefix : String ) {
for( n in _names ) {
print( prefix + n )
}
}
// A public property getter, making 'Names' a read-only property
property get Names() : List<String> {
return _names
}
}
The above code demonstrates the following features:
- The
usesstatement, which is identical to theimportstatement in Java, and makes a class (or package of classes) available for use without qualification. - A class variable, declared using the
varkeyword, just like local variables. Class variables default to private access. You can declare them to bestaticas well. - A class constructor, declared using the
constructkeyword. This constructor allows you to declare new instances ofSampleClasslike so:var c = new SampleClass({"joe", "john", "jack"})Constructors default to public access. - A function, declared using the
functionkeyword. This function takes aStringargument, and returns no value, so no return type declaration is necessary. It can be invoked like so:var c = new SampleClass({"joe", "john", "jack"}) c.printNames("* ") - A property getter, declared using the
propertyandgetkeywords. This property returns a list of strings. It can be invoked like so:var c = new SampleClass({"joe", "john", "jack"}) print( c.Names )
Shorthand Property Syntax
Exposing a field as a property is a common pattern, so there is a short hand syntax for it:
class SampleClass {
var _names : List<String> as Names
// A public constructor
construct( names : List<String> ) {
_names = names
}
// A public function
function printNames( prefix : String ) {
for( n in _names ) {
print( prefix + n )
}
}
}
The 'as Names' bit exposes the _names field as both a readable and writeable a property. If you want the property to be read only, you can add the readonly modifier after the as keyword.
Named Arguments and Default Parameter Values
Gosu supports names arguments and default parameter values to help smooth out APIs. Let's say you wanted to make the argument to printNames() optional, with a default value of "> ". You could change the declaration to:
// A public function
function printNames( prefix : String = "> ") {
for( n in _names ) {
print( prefix + n )
}
}
And now invoke it like so:
var c = new SampleClass({"joe", "john", "jack"})
c.printNames() // No argument is necessary, it will use the default value of "> "
Additionally, Gosu allows you to use named arguments when you are working with non-overloaded methods on Gosu classes:
var c = new SampleClass({"joe", "john", "jack"})
c.printNames(:prefix = "* ")
This can be used to clarify code, so you don't end up with stuff like this:
someMethod(true, false, null, false, true) //bwah?
someMethod( :enableLogging = true, :debug = false,
:contextObject = null, :trace = false,
:summarizeTiming = true) //Oh, I see
Superclasses, Interfaces and Delegates
Gosu classes can extend other classes and implement interfaces, just like in Java, using the extends and implements keywords respectively.
One interesting additional feature of Gosu is the ability to delegate the implementation of an interface to a class variable:
uses java.lang.Runnable
class MyRunnable implements Runnable {
//A delegate, exposed as the Impl property
delegate _runnable represents Runnable
property get Impl : Runnable {
return _runnable
}
property set Impl( r : Runnable ) {
_runnable = r
}
}
MyRunnable does not declare a run() method, like Runnable requires. That's because the delegate field _runnable is implementing the method for it:
var x = new MyRunnable()
x.Impl = new Runnable() {
function run() {
print("Hello, Delegation")
}
}
x.run() // prints "Hello, Delegation"
Delegates give you a convenient way to favor composition over inheritance.