Channels ▼
RSS

Design

Language of the Month: Gosu


The development of Gosu began about nine years ago during the earliest stage of engineering at Guidewire Software. The language's humble origin sprang from an unsuccessful search for a scripting language as the basis for a rule engine we needed to build. Our language criteria didn't seem too demanding; but we were naive. First and foremost, the language had to be embeddable in the JVM and be compatible with leading application servers. It also had to be familiar — the vast majority of programmers are comfortable with imperative, object-oriented languages, and we wanted our scripting language to be the same. We also wanted a language with static typing, so that our customers could edit rules with instant parser feedback and we could provide modern features, such as deterministic code completion, navigation, etc. In addition, we needed to represent our ORM as a set of first-class types in the language, whether it be through code generation or meta-programming or what have you. Lastly, the entity types from our ORM needed to be individually configurable by our customers via custom methods and properties. To our dismay, all the serious scripting languages at that time were dynamically typed, which ruled them out. So began the development of Gosu (which is today an open-source language, available at http://gosu-lang.org).

By the time we had a working language, we started seeing it as a solution for rewriting our company's product UIs, our document management system, our Velocity-template systems; and each step exposed new features that were needed in the language. Of these, by far the most innovative aspect of Gosu is the open type system. Unlike other languages, Gosu's type system is statically extendable to external domains, whereby abstract types can be defined and exposed with first-class representation. This is a big deal and is what makes Gosu extremely vital to the success of our enterprise applications.

Although the type system is what separates Gosu from other JVM languages, we made sure that as a language, Gosu did not suffer from the limitations of so many others. As Java developers, we were and remain to this day feature-starved relative to other languages. Microsoft's C#, for instance, had led the way with productivity boosting features, while Java stagnated or missed the mark. Thus, we borrowed heavily from C# and other languages. Along the way, Gosu picked up properties, type inference, reified (and simplified) generics, composition, closures, eval support, RAII, null-safety, and a host of other useful features. And as you'll soon see, Gosu's syntax is familiar to anyone with Java or C# experience.

One last bit of history involves Gosu's performance. Although Java as a language is showing its age, we can't knock it on performance — it's blazing fast and is still the leader of the pack. Other languages are gaining, but because most are dynamic (e.g., Groovy, JRuby, Jython), they have inherent limits with respect to performance and will never quite approach Java's. For instance, the bytecode they generate for a method call is unconventional and involves a lot of hoop jumping and sophisticated caching techniques. Although a lot of work has gone into the compilers of various dynamic languages, they'll never quite attain the performance of a virtual method call. Gosu was originally a semi-interpreted runtime, but it evolved to be fully bytecode compiled. And because it is statically typed, its compiler generates conventional bytecode, which keeps fair pace with Java. We have more work to do to make areas unique to the language perform even better, but we're comfortable with its performance on the whole.

Features

Variables
From the start, we wanted programmers to feel comfortable with Gosu at first sight. That is, we didn't want to reinvent the wheel or model the language after peripheral or academically motivated languages. Initially, since we were only interested in building a scripting language, we modeled Gosu after the most popular scripting language in use, JavaScript. The syntax is easily understood by most programmers and we could make it statically typed with a few simple changes to its grammar. For instance, local variables are declared with the var keyword and don't require a type declaration if initialized (i.e., the type can be inferred). For example, the following declarations are logically identical:

var name = "fred"
var name : String = "fred"

Java programmers new to Gosu quickly learn to ditch the unnecessary type declarations in favor of type inference. If this is not obvious, consider an example involving generics:

var map : HashMap<String, Company> = new HashMap<String, Company>()

versus:

var map = new HashMap<String, Company>()

Which would you rather read/write?

You've probably noticed the Pascal-style declaration syntax — the type follows the name. Coming from a C-derived language like Java, it may seem awkward at first; but it makes sense coming at it from first principles. Most often, we don't need to see the type; and when present, it is of lesser significance than the name. It feels natural after a bit of exposure.

You may have also noticed the absence of semi-colons as statement terminators. They're optional in Gosu and rarely used.

Classes
When Gosu transitioned from a scripting language to a general-purpose language, it gained types in the form of classes, interfaces, enums, and enhancements. As the next generation of JavaScript (EcmaScript 4) was nearly identical to Java with respect to type declaration syntax, we followed suit. The following example defines a simple class:

package foo.vehicles

uses foo.dealers.Dealer
 
class Car extends Vehicle {
 enum Kind{ Mini, Compact, Mid, Large }
 var _make : Make
 var _kind: Kind
 var _doors : int

 construct( make: Make, kind: Kind, doors: int = 2 ) {
 super()
 _make = make
 _model = model
 _doors = doors
 }
 
 function findQuote( loc: Location, filter(price: int, l: Location) ): Quote{
 …
 }

 property get Make() : Make {
 return _make
 }
 property set Make( value: Make ) {
 _make = value
 }
 …
 
 private static class CarQuote implements Quote {
 …
 }
}
 

As you can see, there are a lot of similarities both structurally and syntactically between Gosu and Java. Just like Java, a statement is required to declare the class's package. Also, uses-statements are required to enable relative type name references used later in the class. The class header syntax is identical to Java's with the exception of access modifiers; Gosu assumes public access in the absence of a modifier. Fields are declared identically to local variables, the default access is private. The construct keyword is used instead of using the class's name. Similarly, the function and property keywords are used to indicate function and property declarations, and both have public default access.

Properties can be defined with shorthand as-clause syntax if they simply reflect the value of a field:

var _make : Make as Make

This syntax is logically equivalent to the explicit declaration of the get/set property methods, which saves a bunch of typing (and reading). Note the capitalization of property names; this is a convention in Gosu.

The source for a class is stored as a file with a .gs extension. And like Java, the source file must reside in a directory structure that reflects the class's package name with respect to the class path.

Programs and Expressions
One convenient byproduct of designing our language from the start as an embeddable scripting language is that we not only have proper types, but we also have free-style scripting in the form of Programs. A program source file has a .gsp extension and is directly executable. So, unlike Java, Gosu doesn't require a boilerplate class with a main() method in order to run some code. Instead, you simply write it and run it. Here's the obligatory Hello World example in Gosu:

print( "Hello World!" )

If need be, your program can access command line parameters dynamically or statically via the built-in CommandLineAccess type.

A program can contain any mix of statements, functions, properties, and classes. But a program doesn't have to exist as a file on disk or execute from the command line. As an embeddable language, Gosu provides services to parse, compile, and execute simple expressions, programs, and templates directly from memory.

Templates
Gosu templates are a lot like JSP templates, but they're built into the language and are represented as first-class types. Here's a quick example:

<html>
<body>
<%
 print( "Evaluating date now" )
 var date = new java.util.Date()
%>
Hello World! The time is now ${date}
</body>
</html>

Templates have a .gst extension and follow the same naming rules as classes and programs. You execute templates by calling static methods on the type. For example, if the preceding template were named "foo.HelloWorld.gst," you could render the template to a String as follows:

var content = foo.HelloWorld.renderToString()

Note you can declare parameters in a template using the params directive. The methods on the template type reflect the parameters statically.

Enhancements
Ever wanted to add methods to an existing type like String or List? That's exactly what enhancements provide. An enhancement looks a lot like a class:

enhancement MyStringEnhancement : String {
 function reverse() : String {
 new StringBuilder( this ).reverse().toString()
 }
}

Just by existing in the classpath, this enhancement adds the reverse() method to Java's String class. In Gosu, you can call it directly:

"Hello".reverse()

An enhancement file has a .gsx extension and follows the same naming rules as classes. An enhancement can contain any number of functions and properties and can also enhance types generically. Note that you never reference enhancements by name in your code. The type system discovers them and modifies type information automatically. Gosu ships with a boatload of core enhancements — mostly around collections, where we leverage closures.

Closures
Functions in Gosu can be first-class values — they can be created anonymously, passed to or returned from other functions,and assigned to variables just like any other type. They can also refer to other variables in the local scope. A value with these properties is called a closure (or lambda) expression or a block or an anonymous function. Call them what you will, they are extremely useful for performing operations on collections. Consider the following Java code:

List<String> names = new ArrayList<String>();
names.add( "Fred" );
names.add( "Barney" );
names.add( "Wilma" );
names.add( "Betty" );
List<String> filteredNames = new ArrayList<String>();
for( String name: names ) {
 if( name.charAt( 0 ) == 'B' ) {
 filteredNames.add( name );
 }
}
return filteredNames;

Ignoring the amount of code to initialize the list (ugh!), filtering it in Java involves manually creating another list, and then iterating over the original one while populating the filtered one. How many times have you written this code? I'll wager too many times. Now consider the equivalent code in Gosu using enhancements with closures:

var names = {"Fred", "Barney", "Wilma", "Betty"}
return names.where( \ e -> e[0] == 'B' )

A lot less typing. And, most importantly, much easier to read.

The syntax is simple. The backslash character "\" signals a closure, followed by parameters, followed by the –> operator, and then an expression or statement. Typically, a closure is a simple expression. In this example, I utilize the where() method defined in an enhancement on Java's Iterable interface. The where() method is declared as follows:

function where( cond(elt:T): boolean ) : List<T< {
  var result = new ArrayList<T>()
  for( elt in this ) {
    if( cond( elt ) ) {
      result.add( elt )
    }
  }
  return result
}

Notice a closure parameter is declared just like a simple parameter with the addition of a parameter list following the name. This particular closure has a parameter with type T, which is a type variable on the enhancement (as it enhances the generic type Iterable). The important thing to understand is that this code is written once and only once. It's tucked away inside an enhancement, so you'll never have to write it (or read it). You only need to concern yourself with the criteria on which you filter your collections.

Composition
Gosu provides direct support for composition as an alternative to inheritance by way of interface delegation.

class Programmer implements Employee, CoderUnit {
 delegate _employee represents Employee = new EmployeeImpl()
 delegate _coder represents CoderUnit = new CoderUnitImpl()

 ...
}

Gosu automatically delegates the implementation of interfaces represented by delegates. It eliminates all the boilerplate code you would otherwise write in Java to do the delegation manually. This small feature enables more flexible architectures based more on composition.

More...
There is not nearly enough space in this article to even touch on all of Gosu's features. In fact, I've barely scratched the surface. I didn't cover Gosu's type inference capabilities, which help reduce code while maintaining excellent readability. Also missing from this discussion are reified generics, RAII support, eval(), intializers, named arguments, intervals, dimensions, improved exception handling, and lots more. Please see the Gosu website for more information.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video