This is the documentation for the Golo programming language.

Copyright and License Notice
Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others

This program and the accompanying materials are made available under the
terms of the Eclipse Public License 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0.

SPDX-License-Identifier: EPL-2.0
Copyright and License Notice for the short code snippets and samples provided in this documentation.
Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others

All rights reserved. This Example Content is intended to demonstrate
usage of Eclipse technology. It is provided to you under the terms and
conditions of the Eclipse Distribution License v1.0 which is available
at http://www.eclipse.org/org/documents/edl-v10.php

1. Basics

Let us start with the Golo basics.

1.1. Editor / IDE support

Editor and IDE support for Golo is available for:

1.2. Hello world

Golo source code need to be placed in modules. Module names are separated with dots, as in:

Foo
foo.Bar
foo.bar.Baz
(...)

It is suggested yet not enforced that the first elements in a module name are in lowercase, and that the last one have an uppercase first letter.

A Golo module can be executable if it has a function named main and that takes an argument for the JVM program arguments:

module hello.World

function main = |args| {
  println("Hello world!")
}

println is a predefined function that outputs a value to the standard console. As you can easily guess, here we output Hello, world! and that is an awesome achievement.

Newlines are important in Golo, so make sure that your editor ends files with a newline.
Golo identifiers can be non-ascii characters (e.g., Japanese, Emoji, Arabic, etc).

1.3. Running "Hello world"

Of course, we need to run this incredibly complex application.

Golo comes with a golo script found in the distribution bin/ folder. It provides several commands, notably:

  • version to query the Golo version, and

  • compile to compile some Golo code to JVM classes, and

  • run to execute some already compiled Golo code, and

  • golo to directly execute Golo code from source files, and

  • diagnose to print compiler internal diagnosis information, and

  • check to check code for compilation errors (e.g. as an editor hook), and

  • doc to generate module(s) documentation, and

  • new to generate new project(s).

The complete commands usage instructions can be listed by running golo --help. A command usage instructions can be listed by running golo --usage ${command}.

The golo script comes with JVM tuning settings that may not be appropriate to your environment. We also provide a vanilla-golo script with no tuning. You may use the $JAVA_OPTS environment variable to provide custom JVM tuning to vanilla-golo.

Provided that golo is available from your current $PATH, you may run the program above as follows:

$ golo golo --files samples/helloworld.golo
Hello world!
$ golo golo --files samples/ --module hello.World
Hello world!
$

golo golo takes several Golo source files (*.golo and directories) as input. It expects the last one to have a main function to call (or use --module to define the golo module with the main function). The Golo code is compiled on the fly and executed straight into a JVM.

You may also pass arguments to the main function by appending --args on the command line invocation. Suppose that we have a module EchoArgs as follows:

module EchoArgs

function main = |args| {
  foreach arg in args {
    println("->  " + arg)
  }
}

We may invoke it as follows:

$ golo golo --files samples/echo-args.golo --args plop da plop
-> plop
-> da
-> plop
$

Note that args is expected to be an array.

Finally, the --classpath flag allows to specify a list of classpath elements, which can be either directories or .jar files. The system property golo.class.path or the environment variable GOLOPATH can also be used to specify these elements. See the golo help command for details on the various Golo commands.

1.4. Compiling Golo source code

Golo comes with a compiler that generates JVM bytecode in .class files. We will give more details in the chapter on interoperability with Java.

Compiling Golo files is straightforward:

$ golo compile --output classes samples/helloworld.golo
$

This compiles the code found in samples/helloworld.golo and outputs the generated classes to a classes folder (it will be created if needed):

$ tree classes/
classes/
└── hello
    └── World.class

1 directory, 1 file
$

It is also possible to output to a Jar archive:

golo compile --output hello.jar samples/*.golo

This would take all .golo files from the sample folder, and assemble the resulting JVM class files in hello.jar.

1.5. Running compiled Golo code

Golo provides a golo command for running compiled Golo code:

$ cd classes
$ golo run --module hello.World
Hello world!
$

Simple, isn’t it?

1.6. Running Golo script

Golo provides a shebang command for running a Golo file as a simple script.

module hello

function main = |args| {
  require(args: length() > 1, "You should set at least one argument!")
  println("Hello " + args: get(1) + " from '" + args: get(0) + "'!")
}

the script above can be executed with:

$ golo shebang hello.golo World
Hello World from 'hello.golo'!
$

Naturally the main goal is to use this command to make the script self-executable:

#!/path/to/golo shebang
module hello

function main = |args| {
  require(args: length() > 1, "You should set at least one argument!")
  println("Hello " + args: get(1) + " from '" + args: get(0) + "'!")
}

Now, we can run the script directly:

$ chmod +x hello.golo
$ ./hello.golo World
Hello World from 'hello.golo'!
$
Golo also provides golosh script that is a shortcut for the golo shebang command, thus a golo script can be hasbanged with env:
#!/usr/bin/env golosh
module hello

function main = |args| {
  require(args: length() > 1, "You should set at least one argument!")
  println("Hello " + args: get(1) + " from '" + args: get(0) + "'!")
}
Each golo and jar files present in the script file’s directory or the sub directories will be scanned. This makes it easy to run scripts and have an automatic classpath for libraries, and automatically compile and load other Golo files.
$ tree ./
./
└── libs
    └── libA.jar
    └── libB.jar
└── commons
    └── utils.golo
    └── others.golo
    └── vendors
        └── otherlib.jar
└── hello.golo
└── library.golo
$

1.7. Passing JVM-specific flags

Both golo and run commands can be given JVM-specific flags using the JAVA_OPTS environment variable.

As an example, the following runs fibonacci.golo and prints JIT compilation along the way:

# Exporting an environment variable
$ export JAVA_OPTS=-XX:+PrintCompilation
$ golo golo --files samples/fibonacci.golo

# ...or you may use this one-liner
$ JAVA_OPTS=-XX:+PrintCompilation golo golo --files samples/fibonacci.golo

1.8. Bash autocompletion

A bash script can be found in share/shell-completion/ called golo-bash-completion that will provide autocomplete support for the golo and vanilla-golo CLI scripts. You may either source the script, or drop the script into your bash_completion.d/ folder and restart your terminal.

Not sure where your bash_completion.d/ folder is? Try /etc/bash_completion.d/ on Linux or /usr/local/etc/bash_completion.d/ for Mac Homebrew users.

1.9. Zsh autocompletion

A zsh script can be found in share/shell-completion/ called golo-zsh-completion that works using the golo-bash-completion to provide autocomplete support using the bash autocomplete support provided by zsh. Place both files into the same directory and source golo-zsh-completion from your terminal or .zshrc to give it a try!

1.10. Comments

Golo comments start with a #, just like in Bash, Python or Ruby:

# This is a comment
println("Plop") # it works here, too

1.11. Variable and constant references

Golo does not check for types at compile time, and they are not declared. Everything happens at runtime in Golo.

Variables are declared using the var keyword, while constant references are declared with let. It is strongly advised that you favour let over var unless you are certain that you need mutability.

Variables and constants need to be initialized when declared. Failing to do so results in a compilation error.

Here are a few examples:

# Ok
var i = 3
i = i + 1

# The assignment fails because truth is a constant
let truth = 42
truth = 666

# Invalid statement, variables / constants have to be initialized
var foo

Valid names contain upper and lower case letters within the [a..z] range, underscores (_), dollar symbols ($) and numbers. In any case, an identifier must not start with a number.

# Ok, but not necessarily great for humans...
let _$_f_o_$$666 = 666

# Wrong!
let 666_club = 666

1.12. Local definitions

It is possible to define a constant reference locally to the evaluation of an expression using the with keyword.

For instance:

let r = [a + 1, a - 1] with { a = 42 }

is functionally equivalent to

let a = 42
let r = [a + 1, a - 1]

However, the a variable exists only in the scope of the expression evaluation. Indeed, code like:

let r = [a + 1, a - 1] with { a = 42 }
println(a)

will not compile since a is unknown in the outer scope.

Besides the locality, this construct is really interesting when constructing other expressions (e.g. match constructs), and can help to keep a functional style form of writing functions.

1.13. Data literals

Golo supports a set of data literals. They directly map to their counterparts from the Java Standard API. We give them along with examples in the data literals table below.

Java type Golo literals

null

null

java.lang.Boolean

true or false

java.lang.String

"hello world"

java.lang.Character

'a', 'b', …​

java.lang.Integer

123, -123, 1_234, …​

java.lang.Long

123_L, -123_L, 1_234_L, …​

java.lang.Double

1.234, -1.234, 1.234e9, …​

java.lang.Float

1.234_F, -1.234_F, 1.234e9_F, …​

java.math.BigInteger

1_B, -42_B, 1_234_B, …​

java.math.BigDecimal

1.0_B, -1_234.56_B, 1.234e-4_B, …​

java.lang.Class

String.class, java.lang.String.class, gololang.Predef.module, byte.class, …​

gololang.FunctionReference

^foo, ^some.module::foo, …​

Speaking of strings, Golo also supports multi-line strings using the """ delimiters, as in:

let text = """This is
a multi-line string.
  How
    cool
      is
        that?"""

println(text)

This snippet would print the following to the standard console output:

This is
a multi-line string.
  How
    cool
      is
        that?

1.14. Collection literals

Golo support special support for common collections. The syntax uses brackets prefixed by a collection name, as in:

let s = set[1, 2, "a", "b"]
let v = vector[1, 2, 3]
let m = map[[1, "a"], [2, "b"]]
# (...)

The syntax and type matchings are the following:

Collection Java type Syntax

Tuple

gololang.Tuple

tuple[1, 2, 3], or simply [1, 2, 3]

Array

java.lang.Object[]

array[1, 2, 3]

List

java.util.LinkedList

list[1, 2, 3]

Vector

java.util.ArrayList

vector[1, 2, 3]

Set

java.util.LinkedHashSet

set[1, 2, 3]

Map

java.util.LinkedHashMap

map[[1, "a"], [2, "b"]]

Range

gololang.Range

[1..10], ['a'..'f']

1.14.1. A note on lists

Since in Golo, every value is actually an instance of Object, there is no overloading, and thus the remove method on lists can’t be used to remove an element at a given position. If you want to remove a list element given its position, use the removeAt method.

1.14.2. A note on tuples

Tuples essentially behave as comparable and immutable arrays.

The gololang.Tuple class provides the following methods:

  • a constructor with a variable-arguments list of values,

  • a get(index) method to get the element at a specified index,

  • a head() method to get the first element,

  • a tail() method returning a copy without the first element,

  • size() and isEmpty() methods that do what their names suggest,

  • an iterator() method because tuples are iterable,

  • toArray() and Tuple.fromArray() for converting between tuples and arrays,

  • subTuple(start, end) to extract a new tuple,

  • extend(…​) to create a new tuple with added values, and

  • equals(other), hashCode() and toString() do just what you would expect.

1.14.3. A note on maps

The map collection literal expects entries to be specified as tuples where the first entry is the key, and the second entry is the value. This allows nested structures to be specified as in:

map[
  ["foo", "bar"],
  ["plop", set[1, 2, 3, 4, 5]],
  ["mrbean", map[
    ["name", "Mr Bean"],
    ["email", "bean@outlook.com"]
  ]]
]

There are a few rules to observe:

  • not providing a series of tuples will yield class cast exceptions,

  • tuples must have at least 2 entries or will yield index bound exceptions,

  • tuples with more than 2 entries are ok, but only the first 2 entries matter.

Because of that, the following code compiles but raises exceptions at runtime:

let m1 = map[1, 2, 4, 5]
let m2 = map[
  [1],
  ["a", "b"]
]

The rationale for map literals to be loose is that we let you put any valid Golo expression, like functions returning valid tuples:

let a = -> [1, 'a']
let b = -> [2, 'b']
let m = map[a(), b()]

1.15. Collection comprehension

In addition to literals, collections can be created using collection comprehension. This is a simple way to create a new collection based on another one (actually on any iterable object), by filtering and transforming its content. For instance:

let l1 = list[1, 2, 3, 4, 5, 6]
let l2 = list[x * 2 foreach x in l1 when (x % 2) == 0]
# l2 == list[4, 8, 12]

This is a more readable and more powerful version of filter+map. The previous example could be rewritten as

let l2 = l2: filter(|x| -> (x % 2) == 0): map(|x| -> x * 2)

The general syntax is a collection literal containing an expression followed by one or more loop-like expression. If more than one loop is given, it is equivalent to nested loops. Thus

let l = list[ [x, y] foreach x in [1..4] foreach y in ["a", "b", "c"] ]

is equivalent to:

let l = list[]
foreach x in [1..4] {
  foreach y in ["a", "b", "c"] {
    l: add([x, y])
  }
}

for loop can be used, as in

let l = list[ 3 * i + 1 for (var i=0, i < 10, i = i + 2) ]

Contrary to the filter+map approach, where the kind on collection is kept, comprehension can transform the source collection type, which can be any iterable. For instance:

let dices = set[ x + y foreach x in [1..7] foreach y in [1..7]]
# dices == set[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

However, the result collection can only be of the type of one of the predefined collection literal types.

Destructuring can also be used in collection comprehension, as in

let couples = [ [1, 2], [2, 3], [3, 4] ]
let sums = [ a + b foreach a, b in couples ]

Maps can also be created, provided the given expression is either a pair tuple or a instance of Map.Entry (you can use the predefined mapEntry(key, value) function to create such objects). For instance:

let myMap = map[ ["key" + i, 2 * i] foreach i in [0..4] ]
# myMap is {key0=0, key1=2, key2=4, key3=6}

A collection comprehension is a expression, and can thus be used as such. E.g.

foreach v in [[x,x] foreach x in [0..3]] {
  println(v)
}

The analogy can be made between comprehension and SQL queries. As an illustration, compare:

select distinct
    p.name, p.age, c.product
from
    persons as p,
    commands as c
where p.id == c.customer
      and p.age > 18

with

let result = set[
  [p: name(), p: age(), c: product()]
  foreach p in persons
  foreach c in commands
  when p: id() == c: customer()
       and p: age() > 18
]

1.15.1. Collection comprehension vs. map and filter

Collection comprehension is actually quite similar to using map and filter higher-order function on a collection. Indeed, a comprehension such as:

list[f(x) foreach x in aList when pred(x)]

is equivalent to

aList: filter(^pred): map(^f)

Thus, should you use collection comprehension or higher-order functions? Despite some implementation differences, it’s above all a matter of taste. Some people consider comprehension more readable, since it is more similar to the mathematical set-builder notation. As an example, compare the two functionally equivalent expressions:

list[ 2 * x for x in aList when (x % 2) == 0 ]
aList: filter(x -> (x % 2) == 0): map(x -> 2 * x)

The more powerful expressiveness of comprehension shines when using nested iterators or destructuring. For instance, an expression such as

list[ k + ": " + (x * v)
    foreach x in [1..10] when (x % 2) == 1
    foreach k, v in aMap:entrySet() when k: startsWith("f") or v >= 42]

would be cumbersome to write using only map and filter.

The comprehension approach has also several advantages. First, while the code executed is almost identical when mapping a function and using a comprehension, that is something similar to

let tmp = list[]
foreach elt in aList {
  tmp: add(f(elt))
}
return tmp

the comprehension code is generated at compile time, whereas the map application is a function called at runtime. As such, when using a filtering clause, the use of filter creates an intermediate list that will be fed to map. This is not the case with comprehension. Moreover, since the expression used to build the values of the new collection is used at compile time, no closure is created, neither for the filter.

An other advantage of comprehension is the fact that it can be used with any iterable, to build a different kind of collection. The map and filter methods are not (yet) available for any iterable, and for those that have them, the result collection is of the same type as the initial one. This approach is more polymorphic, but can be less readable if you need to change the collection type.

1.16. Destructuring

Golo supports simple destructuring, that is automatic extraction of values from an object and assignment to multiple variables in one instruction.

For instance, using destructuring on a tuple:

let a, b = [1, 2]
# a = 1, b = 2

If there are more variables than values, an exception is raised. If there are fewer, the remaining values are ignored. A special syntax is available to assign the rest of the values, similar to varargs notation. For instance:

let a, b, c = [1, 2]               # raises an exception
let a, b = [1, 2, 3]               # a = 1, b = 2, 3 ignored
let a, b, c... = [1, 2, 3, 4, 5]   # a = 1, b = 2, c = [3, 4, 5]

Any object having a destruct() method returning a tuple can be used in destructuring assignments. Golo specific data structures and some Java native ones (arrays, maps, collections) can be destructured. Augmentations can be used to make an existing class destructurable.

For instance, golo structures are destructurable:

struct Point = {x, y}
#...
let p = Point(42, 1337)
let x, y = p   # x = 42, y = 1337

as well as java lists:

let lst = list[1, 2, 3, 4, 5]
let head, tail... = lst        # head = 1, tail = [2, 3, 4, 5]

Already defined variables can also be assigned with destructuring. For instance, one can easily swap two variables:

var a, b = [1, 2]  # a = 1, b = 2
a, b = [b, a]      # a = 2, b = 1

Destucturing can also be used in foreach loops:

foreach key, value in myMap: entrySet() {
  # do something...
}

1.17. Operators

Golo supports the following set of operators.

Symbol(s) Description Examples

+

Addition on numbers and strings.

1 + 2 gives 3.

"foo" + "bar" gives "foobar".

"foo" + something where something is any object instance is equivalent to "foo" + something.toString() in Java.

-

Subtraction on numbers.

4 - 1 gives 3.

*

Multiplication on numbers and strings.

2 * 2 gives 4.

"a" * 3 gives "aaa".

/

Division on numbers.

4 / 2 gives 2.

'%'

Modulo on numbers.

4 % 2 gives 0, 3 % 2 gives 1.

"<", "⇐", "==", "!=", ">", ">="

Comparison between numbers and objects that implement java.lang.Comparable. == is equivalent to calling Object#equals(Object) in Java.

1 < 2 gives true.

is, isnt

Comparison of reference equality.

a is b gives true only if a and b reference the same object instance.

and, or, not

Boolean operators. not is of course a unary operator.

true and true gives true, not(true) gives false.

oftype

Checks the type of an object instance, equivalent to the instanceof operator in Java.

("plop" oftype String.class) gives true.

orIfNull

Evaluates an expression and returns the value of another one if null.

null orIfNull "a" gives "a". foo() orIfNull 0 gives the value of calling foo(), or 0 if foo() returns null.

The algebraic operators can be used with any numeric type having a literal notation (see the data literals table ), including java.math.BigInteger and java.math.BigDecimal.

The operator precedence rules are as follows:

Precedence Operator

Strongest

:, ?:

not

*, /, %

+, -

<, , >, >=, oftype

==, !=, is, isnt

and

or

Lowest

orIfNull

This means that:

not foo: bar() orIfNull "yo"

reads as:

(not (foo: bar())) orIfNull "yo"

1.18. Calling a method

Although we will discuss this in more details later on, you should already know that : is used to invoke instance methods.

You could for instance call the toString() method that any Java object has, and print it out as follows:

println(123: toString())
println(someObject: toString())

1.19. Java / JVM arrays

As you probably know, arrays on the JVM are special objects. Golo deals with such arrays as being instances of Object[] and does not provide a wrapper class like many languages do. A Java / JVM array is just what it is supposed to be.

Golo adds some sugar to relieve the pain of working with arrays. Golo allows some special methods to be invoked on arrays:

  • get(index) returns the value at index,

  • set(index, value) sets value at index,

  • length() and size() return the array length,

  • iterator() returns a java.util.Iterator,

  • toString() delegates to java.util.Arrays.toString(Object[]),

  • asList() delegates to java.util.Arrays.asList(Object[]),

  • equals(someArray) delegates to java.util.Arrays.equals(this, someArray),

  • getClass() returns the array class,

  • head() returns the first element of the array (or null if empty),

  • tail() returns a copy of the array without its first element (or an empty array if empty),

  • isEmpty() checks if the array is empty.

Given a reference a on some array:

# Gets the element at index 0
a: get(0)

# Replaces the element at index 1 with "a"
a: set(1, "a")

# Nice print
println(a: toString())

# Convert to a real collection
let list = a: asList()
The methods above do not perform array bound checks.

Finally, arrays can be created with the Array function, as in:

let a = Array(1, 2, 3, 4)
let b = Array("a", "b")

You can of course take advantage of the array collection literal, too:

let a = array[1, 2, 3, 4]
let b = array["a", "b"]

2. Creating new project(s)

The golo new command can create new Golo project(s):

$ golo new Foo

The command creates a new Golo module named Foo in a main.golo file with a simple function named main that takes an argument for the JVM program arguments.

By default we create a new free-form project but you can specify the type of project with the --type command argument. Three types of projects are currently available:

  • Free-form project,

  • Maven-driven project,

  • Gradle-driven project.

The default value of the --type parameter can be changed by setting the golo.new.type property.

As an example if you want to create a Maven-driven project, just add --type maven:

$ golo new Foo --type maven

By default we create the project directory where the golo command is run. If you need to create your project directory elsewhere you can use the --path command argument:

$ golo new Bar --path /opt/golo

This creates the project directory named Bar in /opt/golo.

2.1. Free-form project

The structure of a free-form project is as follows:

$ tree Foo
Foo
├── imports
├── jars
└── main.golo

2.2. Maven-driven project

The structure of a Maven-driven project is as follows:

$ tree Foo/
Foo/
├── pom.xml
├── README.md
└── src
    ├── main
    │   ├── golo
    │   │   └── main.golo
    │   └── resources
    └── test
        └── golo

The project can be built and packaged with Maven using the following command:

$ mvn package

You can now run the module Foo with:

  • mvn

$ mvn exec:java
  • java

$ java -jar target/Foo-*-jar-with-dependencies.jar
  • golo

$ cd target/classes
$ golo run --module Foo

2.3. Gradle-driven project

The structure of a Gradle-driven project is as follows:

$ tree Foo/
Foo/
├── build.gradle
├── README.md
└── src
    ├── main
    │   ├── golo
    │   │   └── main.golo
    │   └── resources
    └── test
        └── golo

The project can be built and packaged with Gradle using the following command:

$ gradle build

You can now run the module Foo with:

  • gradle

$ gradle run
  • golo

$ cd build/classes/main
$ golo run --module Foo

2.4. Version control

With the --vcs option, the command will create a ignore file and try to initialize the repository. Mercurial (hg) and Git (git) are currently supported. For instance,

$ golo new --vcs git --type gradle Foo
$ tree -a -L 1 Foo/
Foo/
├── build.gradle
├── .git
├── .gitignore
├── README.md
└── src
$ cat Foo/.gitignore
*.class
build/
.gradle/

or

$ golo new --vcs hg --type maven Foo
$ tree -a -L 1 Foo/
Foo/
├── .hg
├── .hgignore
├── pom.xml
├── README.md
└── src
$ cat Foo/.hgignore
syntax: glob
*.class
target/

If the option is not given, or if the value is none, no repository is initialized.

The default value of the --vcs parameter can be changed by setting the golo.new.vcs property.

2.5. Profile

The --profile option defines the kind of project you want to create, and will influence the files and hierarchy generated. Two profiles are currently supported:

  • app will create a application project;

  • lib will create a library project.

3. Functions

Functions are first-class citizen in Golo. Here is how to define and call some.

3.1. Parameter-less functions

Golo modules can define functions as follows:

module sample

function hello = {
  return "Hello!"
}

In turn, you may invoke a function with a familiar notation:

let str = hello()

A function needs to return a value using the return keyword. Some languages state that the last statement is the return value, but Golo does not follow that trend. We believe that return is more explicit, and that a few keystrokes in favour of readability is still a good deal.

Still, you may omit return statements if your function does not return a value:

function printer = {
  println("Hey!")
}

If you do so, the function will actually return null, hence result in the next statement is null:

# result will be null
let result = printer()

3.2. Functions with parameters

Of course functions may take some parameters, as in:

function addition = |a, b| {
  return a + b
}
Parameters are constant references, hence they cannot be reassigned.

Invoking functions that take parameters is straightforward, too:

let three = addition(1, 2)
let hello_world = addition("hello ", "world!")

3.3. Variable-arity functions

Functions may take a varying number of parameters. To define one, just add …​ to the last parameter name:

function foo = |a, b, c...| {
  # ...
}

Here, c catches the variable arguments in an array, just like it would be the case with Java. You can thus treat c as being a Java object of type Object[].

Calling variable-arity functions does not require wrapping the last arguments in an array. While invoking the foo function above, the following examples are legit:

# a=1, b=2, c=[]
foo(1, 2)

# a=1, b=2, c=[3]
foo(1, 2, 3)

# a=1, b=2, c=[3,4]
foo(1, 2, 3, 4)

Because the parameter that catches the last arguments is an array, you may call array methods. Given:

function elementAt = |index, args...| {
  return args: get(index)
}

then:

# prints "2"
println(elementAt(1, 1, 2, 3))

3.4. Named parameters

When you invoke Golo functions, you can use the name of the parameters explicitly in the call like so:

function post = |title, body, promoted, tags...| {
  let data = map[
    ["title", title],
    ["body", body],
    ["promoted", promoted],
    ["tags", tags: asList()]
  ]
  return gololang.JSON.stringify(data)
}

post(
  tags = array["feature", "syntax"],
  body = "it rocks!"
  title = "Named parameters are alive",
  promoted = true
)
Once you are using named parameters in your function call, the order doesn’t matter anymore.
To name varargs argument, you have be box the values into an array[] (just has it’s done with the tags argument in the above snippet)
You must name either or none of the arguments. A compilation error will be raised, if you mix named an unamed arguments in a function invocation.

3.5. Functions from other modules and imports

Suppose that we have a module foo.Bar:

module foo.Bar

function f = {
  return "f()"
}

We can invoke f from another module by prefixing it with its module name:

let r = foo.Bar.f()

Of course, we may also take advantage of an import statement:

module Somewhere.Else

import foo.Bar

function plop = {
  return f()
}
Imports in Golo do not work as in Java. Golo is a dynamic language where symbols are being resolved at runtime. Module imports are not checked at compilation time, and their sole purpose is to help in dynamic resolution. Back to the previous example, f cannot be resolved from the current module, and the Golo runtime subsequently tries to resolve f from each import statement. Also, note that the order of import statements is important, as the resolution stops at the first module having the f function.

You may prepend the last piece of the module name. The following invocations are equivalent:

module Somewhere.Else

import foo.Bar

function plop = {
  let result = f()
  let result_bis = Bar.f()
  let result_full = foo.Bar.f()
  return result
}

To help maintaining packages of several modules, and to avoid repeating the fully qualified name of the package when importing “local” modules, import can also be made relative to the package of the importing module. For instance, the following code:

module foo.bar.Spam

import .baz.Egg

is equivalent to

module foo.bar.Spam

import foo.bar.baz.Egg

Note that only modules in the same package or in a sub-package can be imported using relative name. In the previous example, to import the module foo.Plop, its full name must be specified.

Moreover, it is possible to import several modules from the same package with a single import statement, as in;

import java.util.{Collections, Objects, stream.Collectors}

Golo modules have a set of implicit imports:

  • gololang.Predefined,

  • gololang.StandardAugmentations,

  • gololang,

  • java.lang.

These modules are imported after the module explicitly imported in the module, so that elements defined in these modules (e.g. predefined functions or augmentations) can be redefined.

When an imported module can’t be loaded, either because it is not in the classpath or because of a typo in its name, a warning can printed by setting the golo.warnings.unavailable-class system property to true. This does not preclude the code to work correctly since the looked up function can be present in another imported module. When the function is called prefixed with the module name, and the module can’t be loaded, the warning is also printed, but the code will fail with a NoSuchMethodError. This option is mainly for debugging purpose and is not activated by default. Indeed, due to the way Golo load modules and lookup functions, many “false positives” can be reported. This can be changed in a future release.

3.6. Local functions

By default, functions are visible outside of their module. You may restrict the visibility of a function by using the local keyword:

module Foo

local function a = {
  return 666
}

function b = {
  return a()
}

Here, b is visible while a can only be invoked from within the Foo module. Given another module called Bogus, the following would fail at runtime:

module Bogus

function i_will_crash = {
  return Foo.a()
}

3.7. Recursive Tail Call Optimization

Golo feature recursive tail call optimization. If a function last action is to return the result of a recursive call, it is optimized to not stack a new call and is compiled in code equivalent to a loop. For instance, a function like:

function fact = |acc, v| -> match {
  when v == 0 then acc
  otherwise fact(acc * v, v - 1)
}

is compiled into something roughly equivalent to :

function fact = |acc, v| {
  var acc_ = acc
  var v_ = v
  while v_ != 0 {
    acc_ = acc_ * v_
    v_ = v_ - 1
  }
  return acc_
}

This allows to create recursive functions that will not throw a StackOverflowError even in the presence of a large number or recursive call. The optimization can be disabled by setting the golo.optimize.tce system property to false (e.g. export GOLO_OPTS='-Dgolo.optimize.tce=false).

A call is tail recursive when the function returns the result of calling itself directly. Indeed, since no evaluation nor flow analysis is done, many effectively tail recursive calls can’t be identified as such, and thus are not optimized. It is recommended to rewrite the code to make the tail call more direct. For instance, the following two functions are not optimized:

function foo = |a, v| {
  let r = ^foo
  if v == 0 {
    return a
  }
  return r(a + v, v - 1)
}

function bar = |a, v| {
  var r = null
  if v == 0 {
    r = a
  } else {
    r = bar(a + v, v - 1)
  }
  return r
}

while the following one is:

function ref = |a, v| {
  if v == 0 {
    return a
  }
  return ref(a + v, v - 1)
}

Note that returning a match expression that may evaluate to a tail call will be optimized, such that the function

function baz = |a, v| -> match {
  when v == 0 then a
  otherwise ref(a + v, v - 1)
}

will be strictly equivalent to the previous one. A consequence of this behavior is that mutual recursions are not optimized.

3.7.1. On augmentations

Functions defined in augmentations can be optimized if written in a tail call style. For instance, in the following sample, the reduce function is not optimized since it is viewed as a method call:

struct Cons = {head, tail}

augment Cons {
  function reduce = |this, f, z| -> match {
    when this: isEmpty() then z
    otherwise this: tail(): reduce(f, f(this: head(), z))
  }
}

On the other hand, the following one is optimized and works as expected:

augment Cons {
  function reduce = |this, f, z| -> match {
    when this: isEmpty() then z
    otherwise reduce(this: tail(), f, f(this: head(), z))
  }
}

3.7.2. Limitations on decorators

Since the optimization is done at compile time, most of dynamic features are not available. For instance, decorated functions can’t be optimized. Indeed, in that case, the decorator would not be applied on each call but only on the first one, which could lead to unexpected results.

For instance, the code:

function log = |f| -> |a, v| {
  println("function called with " + a + ", " + v)
  return f(a, v)
}

@log
function fact = |acc, v| -> match {
  when v == 0 then acc
  otherwise fact(acc * v, v - 1)
}

when optimised would print the message only for the first call. The tail call optimization is thus disabled for decorated functions. If the desired behavior is to optimize the function and apply the decorator only for the first call, one can create an undecorated version, and decorate explicitly direct calls or create a decorated wrapper, as in:

function log = |f| -> |a, v| {
  println("function called with " + a + ", " + v)
  return f(a, v)
}

function fact = |acc, v| -> match {
  when v == 0 then acc
  otherwise fact(acc * v, v - 1)
}

@log
function decoratedFact = |acc, v| -> fact(acc, v)

#(...)

let direclyDecorated = log(^fact)
directlyDecorated(1, 5)
log(^fact)(1, 5)

Note that this approach is not as cumbersome, since most of the time, tail recursive functions introduce an “artificial” accumulator that is hidden by a function calling the recursive one with the default accumulator value. For instance, in the factorial case, one would write:

local function fact = |acc, v| -> match {
  when v == 0 then acc
  otherwise fact(acc * v, v - 1)
}

function fact = |v| -> fact(1, v)

or equivalently:

function fact = |n| {
  let _fact = |acc, v| -> match {
    when v == 0 then acc
    otherwise _fact(acc * v, v - 1)
  }
  return _fact(1, n)
}

In this case, the both the local fact and the _fact closure are optimized, while the public one can be decorated.

Similarly, variadic functions are not optimized, since we can’t know at compile-time if the last argument is already an array or a simple value that must be collected. The same kind of approach is recommended, by defining a (local) fixed arguments recursive version that is optimized and a variadic one that delegates on it.

3.8. Module-level state

You can declare let and var references at the module level, as in:

module Sample

let a = 1

var b = truth()

local function truth = {
  return 42
}

These references get initialized when the module is being loaded by the Java virtual machine. In fact, module-level state is implemented using private static fields that get initialized in a <clinit> method.

Module-level references are only visible from their module, although a function may provide accessors to them.

It is important to note that such references get initialized in the order of declaration in the source file. Having initialization dependencies between such references would be silly anyway, but one should keep it in mind just in case.

Global state is a bad thing in general. We strongly advise you to think twice before you introduce module-level state. Beware of potential memory leaks, just like static class fields in the Java programming language.

4. Java interoperability

Golo aims at providing a seamless 2-way interoperability with the Java programming language.

4.1. Main function Java compliance

If the Golo compiler find a unary function named main, it will be compiled to a void(String[]) static method. This main method can servers as a JVM entry point.

Suppose that we have the following Golo module:

module mainEntryPoint


function main = |args| {
  println("-> " + args: get(0))
}

Once compiled, we may invoke it as follows:

$ golo compile mainEntryPoint.golo
$ java -cp ".:golo.jar" mainEntryPoint GoloRocks
-> GoloRocks
$

4.2. Calling static methods

Golo can invoke public Java static methods by treating them as functions:

module sample

import java.util.Arrays

function oneTwoThree = {
  return asList(1, 2, 3)
}

In this example, asList is resolved from the java.util.Arrays import and called as a function. Note that we could equivalently have written a qualified invocation as Arrays.asList(1, 2, 3).

4.3. Calling instance methods

When you have an object, you may invoke its methods using the : operator.

The following would call the toString method of any kind, then print it:

println(">>> " + someObject: toString())

Of course, you may chain calls as long as a method is not of a void return type. Golo converts Java void methods by making them return null. This is neither a bug or a feature: the invokedynamic support on the JVM simply does so.

4.4. Named arguments

If you compile your Java 8 source code with the -parameters option, then you will be able to invoke the functions from Golo with named arguments.

package io;

public class Printer {
 public static Object print(Object prefix, Object what) {
    System.out.println(prefix +  " " + what);
    return null;
 }
}
$ javac -parameters Printer.java
module bar
import io.Printer

let obj = DynamicObject()

function main = |args...| {
  print(what = obj, prefix = ">")
}

Further documentation about Names Method Parameters with Java 8.

If the java code was not compiled with named parameters, the named arguments syntax is still valid, but the names are simply ignored and no reordering will be done. You can therefore use the argument names to improve readability and with the hope that the java library you use will later be compiled with the options, but keep them in the expected order, or you could have unexpected results.

A warning is displayed when named arguments are used with functions without named parameters. It can be disabled by setting the golo.warnings.no-parameter-names system property to false.

4.5. Deprecated method

When calling a deprecated method or function, a warning is displayed. It can be disabled by setting the golo.warnings.deprecated system property to false.

4.6. null-safe instance method invocations

Golo supports null-safe methods invocations using the "Elvis" symbol: ?:.

Suppose that we invoke the method bar() on some reference foo: foo: bar(). If foo is null, then invoking bar() throws a java.lang.NullPointerException, just like you would expect in Java.

By contrast:

  • foo?: bar() simply returns null, and

  • null?: anything() returns null, too.

This is quite useful when querying data models where null values could be returned. This can be elegantly combined with the orIfNull operator to return a default value, as illustrated by the following example:

let person = dao: findByName("Mr Bean")
let city = person?: address()?: city() orIfNull "n/a"

This is more elegant than, say:

let person = dao: findByName("Mr Bean")
var city = "n/a"
if person isnt null {
  let address = person: address()
  if address isnt null {
    city = address: city() ofIfNull "n/a"
  }
}
The runtime implementation of null-safe method invocations is optimistic as it behaves like a try block catching a NullPointerException. Performance is good unless most invocations happen to be on null, in which case using ?: is probably not a great idea.

4.7. Creating objects

Golo doesn’t have an instantiation operator like new in Java. Instead, creating an object and calling its constructor is done as if it was just another function.

As an example, we may allocate a java.util.LinkedList as follows:

module sample

import java.util

function aList = {
  return LinkedList()
}

Another example would be using a java.lang.StringBuilder.

function str_build = {
  return java.lang.StringBuilder("h"):
    append("e"):
    append("l"):
    append("l"):
    append("o"):
    toString()
}

As one would expect, the str_build function above gives the "hello" string.

4.8. Static fields

Golo treats public static fields as function, so one could get the maximum value for an Integer as follows:

module samples.MaxInt

local function max_int = {
  return java.lang.Integer.MAX_VALUE()
}

function main = |args| {
  println(max_int())
}
Given than most static fields are used as constants in Java, Golo does not provide support to change their values. This may change in the future if compelling general-interest use-cases emerge.

4.9. Instance fields

Instance fields can be accessed as functions, both for reading and writing. Suppose that we have a Java class that looks as follows:

public class Foo {
  public String bar;
}

We can access the bar field as follows:

let foo = Foo()

# Write
foo: bar("baz")

# Read, prints "baz"
println(foo: bar())

An interesting behavior when writing fields is that the "methods" return the object, which means that you can chain invocations.

Suppose that we have a Java class as follows:

public class Foo {
  public String bar;
  public String baz;
}

We can set all fields by chaining invocations as in:

let foo = Foo(): bar(1): baz(2)

It should be noted that Golo won’t bypass the regular Java visibility access rules on fields.

What happens if there is both a field and a method with the same names?

Back to the previous example, suppose that we have both a field and a method with the same name, as in:

public class Foo {
  public String bar;

  public String bar() {
    return bar;
  }
}

Golo resolves methods first, fields last. Hence, the following Golo code will resolve the bar() method, not the bar field:

let foo = Foo()

# Write the field
foo: bar("baz")

# Calls the bar() method
println(foo: bar())

4.10. Properties support

Golo support property-style method calls.

Given a property name(), Golo will translate the method call to a {get|is or set}Name method call. Obviously, if a field is not accessible (ie. private) and doesn’t have a getter or setter, the resolution will fail. Finally, write-only properties can be chained (ie: return the current this instance), unless a return value is defined in the according setter method.

The property resolution does not check if an according field exists. Basically all the get|set|is| methods are candidates to a property-style method invocation.
public class Person {

  private String name;
  private boolean goloComitter;
  private String email;
  private int score;

  public String getName() {
  ...
  }

  public boolean isGoloComitter() {
  ...
  }

  public void setName(String name) {
    ...
  }

  public void setGoloCommitter(boolean goloCommitter) {
  ...
  }

  public int setScore(int score) {
    this.score = score;
    return score;
  }

  public boolean isRockStar() {
    return goloCommitter;
  }
}
let duke = Person()

try {
  duke: email("duke@golo-lang.org")
} catch (e) {
  require(e oftype java.lang.NoSuchMethodError.class, "the email field is private and no setter is defined")
}

require(duke: name("Duke"): goloCommiter(true) oftype Person.class, "the set mutators should be chained with fluent calls")
require(duke: name() is "Duke", "should find the getName() accessor.")
require(duke: goloCommitter() is true, "should invoke the isGoloCommitter accessor since the field it's a boolean")
require(print(duke: rockStar() is true, "even if the field rockstar doesn't exists, it should invoke the isRockStar accessor")
require(ducke: score(100) is 100, "setScore returns a value, the method isn't fluent")

4.11. Inner classes and enumerations

We will illustrate both how to deal with public static inner classes and enumerations at once.

The rules to deal with them in Golo are as follows.

  1. Inner classes are identified by their real name in the JVM, with nested classes being separated by a $ sign. Hence, Thread.State in Java is written Thread$State in Golo.

  2. Enumerations are just normal objects. They expose each entry as a static field, and each entry is an instance of the enumeration class.

Let us consider the following example:

module sample.EnumsThreadState

import java.lang.Thread$State

function main = |args| {

  # Call the enum entry like a function
  let new = Thread$State.NEW()
  println("name=" + new: name() + ", ordinal=" + new: ordinal())

  # Walk through all enum entries
  foreach element in Thread$State.values() {
    println("name=" + element: name() + ", ordinal=" + element: ordinal())
  }
}

Running it yields the following console output:

$ golo golo --files samples/enums-thread-state.golo
name=NEW, ordinal=0
name=NEW, ordinal=0
name=RUNNABLE, ordinal=1
name=BLOCKED, ordinal=2
name=WAITING, ordinal=3
name=TIMED_WAITING, ordinal=4
name=TERMINATED, ordinal=5
$

4.12. Clashes with Golo operators and escaping

Because Golo provides a few named operators such as is, and or not, they are recognized as operator tokens.

However, you may find yourself in a situation where you need to invoke a Java method whose name is a Golo operator, such as:

# Function call
is()

# Method call
someObject: foo(): is(): not(): bar()

This results in a parsing error, as is and not will be matched as operators instead of method identifiers.

The solution is to use escaping, by prefixing identifiers with a backtick, as in:

# Function call
`is()

# Method call
someObject: foo(): `is(): `not(): bar()

4.13. Golo class loader

Golo provides a class loader for directly loading and compiling Golo modules. You may use it as follows:

import org.eclipse.golo.compiler.GoloClassLoader;

public class Foo {

  public static void main(String... args) throws Throwable {
    GoloClassLoader classLoader = new GoloClassLoader();
    Class<?> moduleClass = classLoader.load("foo.golo", new FileInputStream("/path/to/foo.golo"));
    Method bar = moduleClass.getMethod("bar", Object.class);
    bar.invoke(null, "golo golo");
  }
}

This would work with a Golo module defined as in:

module foo.Bar

function bar = |wat| -> println(wat)

Indeed, a Golo module is viewable as a Java class where each function is a static method.

GoloClassLoader is rather dumb at this stage, and you will get an exception if you try to load two Golo source files with the same module name declaration. This is because it will attempt to redefine an already defined class.
Later in the glorious and glamorous future, Golo will have objects and not just functions. Be patient, it’s coming in!

4.14. Primitive Data Types

java.lang.Class instances of primitive data types can be obtained as in Java way: byte.class, short.class, int.class, long.class, float.class, double.class, boolean.class and char.class.

This could be useful for example to deal with primitive arrays:

# ...
let buffer = newTypedArray(byte.class, 1024)
let read = inputstream: read(buffer)
# ...

5. Control flow

Control flow in Golo is imperative and has the usual constructions found in upstream languages.

5.1. Conditional branching

Golo supports the traditional if / else constructions, as in:

if goloIsGreat() {
  println("Golo Golo")
}

if (someCondition) {
  doThis()
} else if someOtherCondition {
  doThat()
} else {
  doThatThing()
}

The condition of an if statement does not need parenthesis. You may add some to clarify a more elaborated expression, though.

5.2. case branching

Golo offers a versatile case construction for conditional branching. It may be used in place of multiple nested if / else statements, as in:

function what = |obj| {
  case {
    when obj oftype String.class {
      return "String"
    }
    when obj oftype Integer.class {
      return "Integer"
    }
    otherwise {
      return "alien"
    }
  }
}

A case statement requires at least 1 when clause and a mandatory otherwise clause. Each clause is being associated with a block. It is semantically equivalent to the corresponding if / else chain:

function what = |obj| {
  if obj oftype String.class {
    return "String"
  } else if obj oftype Integer.class {
    return "Integer"
  } else {
    return "alien"
  }
}
when clauses are being evaluated in the declaration order, and only the first satisfied one is being executed.

5.3. match expressions

The match expression is a convenient shortcut for cases where a case statement would be used to match a value, and give back a result. While it may resemble pattern matching operators in some other languages it is not fully equivalent, as Golo does not support full destructuring matching (but with can help here).

match is a great addition to the Golo programmer:

let item = "foo@bar.com"

let what_it_could_be = -> match {
  when item: contains("@") then "an email?"
  when item: startsWith("+33") then "a French phone number?"
  when item: startsWith("http://") then "a website URL?"
  otherwise "I have no clue, mate!"
}

# prints "an email?"
println(what_it_could_be(item))

The values to be returned are specified after a then keyword that follows a boolean expression to be evaluated.

Like case statements, a match construct needs at least one when clause and one otherwise clause.

5.4. while loops

While loops in Golo are straightforward:

function times = |n| {
  var times = 0
  while (times < n) { times = times + 1 }
  return times
}

The parenthesis in the while condition may be omitted like it is the case for if statements.

5.5. for loops

This is the most versatile loop construction, as it features:

  1. a variable declaration and initialization (a Golo variable is always initialized anyway), and

  2. a loop progress condition, and

  3. a loop progress statement.

The following function shows a for loop:

function fact = |value, n| {
  var result = 1
  for (var i = 0, i < n, i = i + 1) {
    result = result * value
  }
  return result
}

As you can see, it is very much like a for loop in Java, except that:

  • the for loop elements are separated by ',' instead of ';', and

  • there cannot be multiple variables in the loop, and

  • there cannot be multiple loop progress statements.

Again, this choice is dictated by the pursue of simplicity.

5.6. foreach loops

Golo provides a "for each" style of iteration over iterable elements. Any object that is an instance of java.lang.Iterable can be used in foreach loops, as in:

function concat_to_string = |iterable| {
  var result = ""
  foreach item in iterable {
    result = result + item
  }
  return result
}

In this example, item is a variable within the foreach loop scope, and iterable is an object that is expected to be iterable.

You may use parenthesis around a foreach expression, so foreach (foo in bar) is equivalent to foreach foo in bar.

Although Java arrays (Object[]) are not real objects, they can be used with foreach loops. Golo provides a iterator() method for them.

5.7. foreach loops with a guard

There is a variant of the foreach loop with a when guard.

The following code:

foreach item in collection {
  if item < 10 {
    println(item)
  }
}

can be simplified as:

foreach item in collection when item < 10 {
  println(item)
}

The when guard can be any expression that evaluates to a boolean.

5.8. break and continue

Although not strictly necessary, the break and continue statements can be useful to simplify some loops in imperative languages.

Like in Java and many other languages:

  • break exits the current inner-most loop, and

  • continue skips to the next iteration of the current inner-most loop.

Consider the following contrived example:

module test

function main = |args| {
  var i = 0
  while true {
    i = i + 1
    if i < 40 {
      continue
    } else {
      print(i + " ")
    }
    if i == 50 {
      break
    }
  }
  println("bye")
}

It prints the following output:

40 41 42 43 44 45 46 47 48 49 50 bye

Golo does not support break statements to labels like Java does. In fact, this is a goto statement in disguise.

5.9. Why no value from most control flow constructions?

Some programming languages return values from selected control flow constructions, with the returned value being the evaluation of the last statement in a block. This can be handy in some situations such as the following code snippet in Scala:

println(if (4 % 2 == 0) "even" else "odd")

The Golo original author recognizes and appreciates the expressiveness of such construct. However, he often finds it harder to spot the returned values with such constructs, and he thought that trading a few keystrokes for explicitness was better than shorter construct based in implicitness.

Therefore, most Golo control flow constructions do not return values, and programmers are instead required to extract a variable or provide an explicit return statement.

6. Exceptions

Exception handling in Golo is simple. There is no distinction between checked and unchecked exceptions.

6.1. Raising exceptions

Golo provides 2 predefined functions for raising exceptions:

  • raise(message) throws a java.lang.RuntimeException with a message given as a string, and

  • raise(message, cause) does the same and specifies a cause which must be an instance of java.lang.Throwable.

Throwing an exception is thus as easy as:

if somethingIsWrong() {
  raise("Woops!")
}

6.2. Raising specialized exceptions

Of course not every exception shall be an instance of java.lang.RuntimeException. When a more specialized type is required, you may simply instantiate a Java exception and throw it using the throw keyword as in the following example:

module golotest.execution.Exceptions

import java.lang.RuntimeException

function runtimeException = {
  throw RuntimeException("w00t")
}

6.3. Exception handling

Exception handling uses the familiar try / catch, try / catch / finally and try / finally constructions. Their semantics are the same as found in other languages such as Java, especially regarding the handling of finally blocks.

The following snippets show each exception handling form.

# Good old try / catch
try {
  something()
} catch (e) {
  e: printStackTrace()
}

# A try / finally
try {
  doSomething()
} finally {
  cleanup()
}

# Full try / catch / finally construct
try {
  doSomething()
} catch (e) {
  e: printStackTrace()
  case {
    when e oftype IOException.class {
      println("Oh, an I/O exception that I was expecting!")
    }
    when e oftype SecurityException.class {
      println("Damn, I didn't expect a security problem...")
      throw e
    }
    otherwise {
      throw e
    }
  }
} finally {
  cleanup()
}
Because Golo is a weakly typed dynamic language, you need to check for the exception type with the oftype operator. In a statically typed language like Java, you would instead have several catch clauses with the exception reference given a specific type. We suggest that you take advantage of the case branching statement.

7. Closures

Golo supports closures, which means that functions can be treated as first-class citizen.

7.1. Defining and using a closure

Defining a closure is straightforward as it derives from the way a function can be defined:

let adder = |a, b| {
  return a + b
}

At runtime, a closure is an instance of gololang.FunctionReference, which is essentially a boxing of java.lang.invoke.MethodHandle. This means that you can do all the operations that method handles support, such as invoking them or inserting arguments as illustrated in the following example:

let adder = |a, b| {
  return a + b
}
println(adder: invoke(1, 2))

let addToTen = adder: bindTo(10)
println(addToTen: invoke(2))

As one would expect, this prints 3 and 12.

In order to make closure’s invocations more fluent you can insert argument using the closure’s parameter names.

let mul = |a, b| {
  return a * b
}

let tenTimes = mul: bindAt("a", 10)
# 20
println(tenTimes: invoke(2))

7.2. Compact closures

Golo supports a compact form of closures for the cases where their body consists of a single expression. The example above can be simplified as:

let adder = |a, b| -> a + b

You may also use this compact form when defining regular functions, as in:

module Foo

local function sayHello = |who| -> "Hello " + who + "!"

# Prints "Hello Julien!"
function main = |args| {
  println(sayHello("Julien"))
}

7.3. Calling closures

While you may call function references using invoke, there is a (much) better way.

When you have a reference to a closure, you may simply call it as a regular function. The previous adder example can be equivalently rewritten as:

let adder = |a, b| -> a + b
println(adder(1, 2))

let addToTen = adder: bindTo(10)
println(addToTen(2))

7.4. Limitations

Closures have access to the lexical scope of their defining environment. Consider this example:

function plus_3 = {
  let foo = 3
  return |x| -> x + foo
}

The plus_3 function returns a closure that has access to the foo reference, just as you would expect. The foo reference is said to have been captured and made available in the closure.

It is important to note that captured references are constants within the closure. Consider the following example:

var a = 1
let f = {
  a = 2   # Compilation error!
}

The compilation fails because although a is declared using var in its original scope, it is actually passed as an argument to the f closure. Because function parameters are implicitly constant references, this results in a compilation error.

That being said, a closure has a reference on the same object as its defining environment, so a mutable object is a sensible way to pass data back from a closure as a side-effect, as in:

let list = java.util.LinkedList()
let pump_it = {
  list: add("I heard you say")
  list: add("Hey!")
  list: add("Hey!")
}
pump_it()
println(list)

which prints [I heard you say, Hey!, Hey!].

7.5. Closures to single-method interfaces

The Java SE APIs have plenty of interfaces with a single method: java.util.concurrent.Callable, java.lang.Runnable, javax.swing.ActionListener, etc.

The predefined function asInterfaceInstance can be used to convert a method handle or Golo closure to an instance of a specific interface.

Here is how one could pass an action listener to a javax.swing.JButton:

let button = JButton("Click me!")
let handler = |event| -> println("Clicked!")
button: addActionListener(asInterfaceInstance(ActionListener.class, handler))

Because the asInterfaceInstance call consumes some readability budget, you may refactor it with a local function as in:

local function listener = |handler| -> asInterfaceInstance(ActionListener.class, handler)

# (...)
let button = JButton("Click me!")
button: addActionListener(listener(|event| -> println("Clicked!")))

Here is another example that uses the java.util.concurrent APIs to obtain an executor, pass it a task, fetch the result with a Future object then shut it down:

function give_me_hey = {
  let executor = Executors.newSingleThreadExecutor()
  let future = executor: submit(asInterfaceInstance(Callable.class, -> "hey!"))
  let result = future: get()
  executor: shutdown()
  return result
}

7.6. Closures to Java 8 functional interfaces

Java 8 introduced support for the so-called lambdas. The mechanism works through functional interfaces, that is, interfaces with a single abstract method that are annotated with @FunctionalInterface.

Golo provides a asFunctionalInterface pre-defined function to convert closures and that works like the asInterfaceInstance function:

let always_true = asFunctionalInterface(java.lang.function.Predicate.class, |obj| -> true)

7.7. Direct closure passing works

When a function or method parameter of a Java API expects a single method interface type or a functional interface, you can pass a closure directly, as in:

# Swing action listeners, a classic!
let button = JButton("Click me!")
button: addActionListener(|event| -> println("Clicked!"))

# Java 8 streams / lambdas interop
let result = list[1, 2, 3, 4, 5]:
  stream():
  map(|n| -> n * 10):
  reduce(0, |acc, next| -> acc + next)

Note that this causes the creation of a method handle proxy object for each function or method invocation. For performance-sensitive contexts, we suggest that you use either asInterfaceInstance, the to conversion method described hereafter, or asFunctionalInterface.

7.8. Conversion to single-method interfaces

Instead of using asInterfaceInstance, you may use a class augmentation which is described later in this documentation. In short, it allows you to call a to method on instances of MethodHandle, which in turn calls asInterfaceInstance. Back to the previous examples, the next 2 lines are equivalent:

# Calling asInterfaceInstance
future = executor: submit(asInterfaceInstance(Callable.class, -> "hey!"))

# Using a class augmentation
future = executor: submit((-> "hey!"): to(Callable.class))

7.9. Getting a reference to a closure / Golo function

You may also take advantage of the predefined fun function to obtain a reference to a closure, as in:

import golotest.Closures

local function local_fun = |x| -> x + 1

function call_local_fun = {

  # local_fun, with a parameter
  var f = fun("local_fun", golotest.Closures.module, 1)

  # ...or just like this if there is only 1 local_fun definition
  f = fun("local_fun", golotest.Closures.module)

  return f(1)
}

Last but not least, we have an even shorter notation if function are not overridden:

import golotest.Closures

local function local_fun = |x| -> x + 1

function call_local_fun = {

  # In the current module
  var f = ^local_fun

  # ...or with a full module name
  f = ^golotest.Closures::local_fun

  return f(1)
}

If the function is overridden, that is several functions exist with the same name but different arities, you must specify the arity with the notation ^moduleName::functionName\arity. For instance:

local function foo = |a, b| -> a * b

local function foo = |x| -> x + 1

function call_foo = {
  return ^foo\2(^foo\1(20), 2)
}

In this case, one can even specify if a varargs function is needed or not (since arity alone can be ambiguous) using final …​:

local function foo = |a| -> "unary"
local function foo = |a...| -> "variable"

^foo\1(null) # unary
^foo\1...()  # variable

Note that you can in the same way get a reference to a Java static method. For instance:

list["Foo", null, 42]: filter(^java.util.Objects::nonNull)

You can also get a reference to a non-static method. In this case, the function will accept an instance of the class as first argument, as in:

list["Foo", "Bar", "Hello", "Goodbye"]: map(^String::length)

7.10. Binding and composing

You can bind a function first argument using the bindTo(value) method. If you need to bind an argument at another position than 0, you may take advantage of bindAt(position, value):

let diff = |a, b| -> a - b
let minus10 = diff: bindAt(1, 10)

# 10
println(minus10(20))

You may compose functions using the andThen method:

let f = (|x| -> x + 1): andThen(|x| -> x - 10): andThen(|x| -> x * 100)

# -500
println(f(4))

or:

function foo = |x| -> x + 1
function bar = |x| -> 2 * x

function main = |args| {
  let newFunction = ^foo: andThen(^bar)

  # 8
  println(newFunction(3))
}

7.11. Calling functions that return functions

Given that functions are first-class objects in Golo, you may define functions (or closures) that return functions, as in:

let f = |x| -> |y| -> |z| -> x + y + z

You could use intermediate references to use the f function above:

let f1 = f(1)
let f2 = f1(2)
let f3 = f2(3)

# Prints '6'
println(f3())

Golo supports a nicer syntax if you don’t need intermediate references:

# Prints '6'
println(f(1)(2)(3)())

8. Predefined functions

Every Golo module definition comes with gololang.Predefined as a default import. It provides useful functions.

8.1. Console output

print and println do just what you would expect.

print("Hey")
println()

println("Hey")

8.2. Console input

readln() or readln(strMessage) reads a single line of text from the console. It always returns a string.

readPassword() or readPassword(strPassword) reads a password from the console with echoing disabled. It always returns a string. There are also secureReadPassword() and secureReadPassword(strPassword) variants that return a char[] array.

let name = readln("what's your name? ")
let value = readln()
let pwd = readPassword("type your password:")
As of Golo 3.3, these functions are in the gololang.IO module, and those in gololang.Predefined are deprecated. They will be removed in Golo 4.0.

8.3. File I/O

Sometimes it is very desirable to read the content of a text file. The fileToText function does just that:

let text = fileToText("/some/file.txt", "UTF-8")

The first parameter is either a java.lang.String, a java.io.File or a java.nio.file.Path. The second parameter represents the encoding charset, either as a java.lang.String or a java.nio.charset.Charset.

We can write some text to a file, too:

textToFile("Hello, world!", "/foo/bar.txt")

The textToFile function overwrites existing files, and creates new ones if needed.

These functions are provided for convenience, so if you need more fine-grained control over reading and writing text then we suggest that you look into the java.nio.file package.

In addition, if you need to verify that a file exists, you can use the fileExists function.

if fileExists("/foo/bar.txt") {
  println("file found!")
}

As in the other File I/O methods, the parameter is either a java.lang.String, a java.io.File or a java.nio.file.Path. The fileExists function will return true if the file exists, false if it doesn’t.

If you need the current path of execution, you can use the currentDir function.

println(currentDir())
As of Golo 3.3, these functions are in the gololang.IO module, and those in gololang.Predefined are deprecated.

8.4. Number type conversions

The following functions convert any number of string value to another number type: intValue(n), longValue(n), charValue(n), doubleValue(n) and floatValue(n).

The usual Java type narrowing or widening conventions apply.

let i = intValue("666")   # 666 (string to integer)
let j = intValue(1.234)   # 1 (double to integer)
let k = intValue(666_L)   # 666 (long to integer)
# etc

8.5. Exceptions

raise can be used to throw a java.lang.RuntimeException. It comes in two forms: one with a message as a string, and one with a message and a cause.

try {
  ...
  raise("Somehow something is wrong")
} catch (e) {
  ...
  raise("Something was wrong, and here is the cause", e)
}

8.6. Preconditions

Preconditions are useful, especially in a dynamically-typed language.

require can check for a boolean expression along with an error message. In case of error, it throws an AssertionError.

function foo = |a| {
  require(a oftype String.class, "a must be a String")
  ...
}

You may also use requireNotNull that…​ well…​ checks that its argument is not null:

function foo = |a| {
  requireNotNull(a)
  ...
}

8.7. Arrays

Golo arrays can be created using the array[…​] literal syntax. Such arrays are of JVM type Object[].

There are cases where one needs typed arrays rather than Object[] arrays, especially when dealing with existing Java libraries.

The newTypedArray predefined function can help:

let data = newTypedArray(java.lang.String.class, 3)
data: set(0, "A")
data: set(1, "B")
data: set(2, "C")

8.8. Ranges

The range function yields an iterable range over either Integer, Long or Character bounds:

# Prints 1 2 (...) 100
foreach i in range(1, 101) {
  print(i + " ")
}

# Prints a b c d
foreach c in range('a', 'e') {
  print(c + " ")
}

let r = range(0, 6): incrementBy(2)
println("Start: " + r: from())
println("End: " + r: to())
foreach i in r {
  println(i)
}

println("Increment: " + r: increment())

The lower bound is inclusive, the upper bound is exclusive.

A range with a lower bound greater than its upper bound will be empty, except if the increment is explicitly negative:

# Prints nothing
foreach i in range(3, 0) {
  print(i + " ")
}

# Prints 3 2 1
foreach i in range(3, 0): incrementBy(-1) {
  print(i + " ")
}

# Prints 0 -2 -4
foreach i in range(0, -6):decrementBy(2) {
  print(i + " ")
}

The reversedRange function is an alias for range with an increment of -1, such that reversedRange(5, 1) is the same as range(5, 1): decrementBy(1).

When range is called with only one value, it is used as the upper bound, the lower one being a default value (0 for numbers, 'A' for chars). For example, range(5) == range(0, 5) and range('Z') == range('A', 'Z'). In the same way, reversedRange(5) == reversedRange(5, 0).

Two ranges are equals if they have the same bounds and increment.

A range can also be defined with the literal notation [begin..end], which is equivalent to range(begin, end).

8.9. Closures

Given a function reference, one can convert it to an instance of an interface with a single method declaration, as in:

local function listener = |handler| -> asInterfaceInstance(ActionListener.class, handler)

# (...)
let button = JButton("Click me!")
button: addActionListener(listener(|event| -> println("Clicked!")))

It is possible to test if an object is a closure or not with the isClosure function. This is useful to support values and delayed evaluation, as in:

if isClosure(value) {
  map: put(key, value())
} else {
  map: put(key, value)
}

You can get a reference to a closure using the predefined fun function:

import golotest.Closures

local function local_fun = |x| -> x + 1

function call_local_fun = {
  let f = fun("local_fun", golotest.Closures.module)
  return f(1)
}

Because functions may be overloaded, there is a form that accepts an extra parameter for specifying the number of parameters:

import golotest.Closures

local function local_fun = |x| -> x + 1

function call_local_fun = {
  let f = fun("local_fun", golotest.Closures.module, 1)
  return f(1)
}

While asInterfaceInstance works for single-method interfaces, Java 8 introduced default methods and functional interfaces to support the so-called lambda expressions.

The asFunctionalInterface function is similar to asInterfaceInstance and supports these types of adaptations:

let always_true = asFunctionalInterface(java.lang.function.Predicate.class, |obj| -> true)

8.10. Array types

Golo does not provide a literal syntax for array types, such as Object[].class in Java.

Instead, we provide 3 helper functions.

  • isArray(object): returns a boolean if object is an array.

  • objectArrayType(): returns Object[].class.

  • arrayTypeOf(type): given type as a java.lang.Class, returns type[].class.

8.11. Misc.

mapEntry gives instances of java.util.AbstractMap.SimpleEntry, and is used as follows:

let e = mapEntry("foo", "bar")

# prints "foo => bar"
println(e: key() + " => " + e: value())

box gives instances of java.util.concurrent.atomic.AtomicReference, and can be used to create a mutable reference where not possible otherwise, e.g. in closures, as in:

function counter = |init, stepFun| {
  let current = box(init)
  return -> current: getAndUpdate(stepFun)
}
#...
let c2 = counter(3, |x| -> x * 2)
c() # -> 3
c() # -> 6
c() # -> 12

9. Class augmentations

Many dynamic languages support the ability to extend existing classes by adding new methods to them. You may think of categories in Objective-C and Groovy, or open classes in Ruby.

This is generally implemented by providing meta-classes. When some piece of code adds a method foo to, say, SomeClass, then all instances of SomeClass get that new foo method. While very convenient, such an open system may lead to well-known conflicts between the added methods.

Golo provides a more limited but explicit way to add methods to existing classes in the form of class augmentations.

9.1. Wrapping a string with a function

Let us motivate the value of augmentations by starting with the following example. Suppose that we would like a function to wrap a string with a left and right string. We could do that in Golo as follows:

function wrap = |left, str, right| -> left + str + right

# (...)
let str = wrap("(", "foo", ")")
println(str) # prints "(abc)"

Defining functions for such tasks makes perfect sense, but what if we could just add the wrap method to all instances of java.lang.String instead?

9.2. Augmenting classes

Defining an augmentation is a matter of adding a augment block in a module:

module foo

augment java.lang.String {
  function wrap = |this, left, right| -> left + this + right
}

function wrapped = -> "abc": wrap("(", ")")

More specifically:

  1. a augment definition is made on a fully-qualified class name, and

  2. an augmentation function takes the receiver object as its first argument, followed by optional arguments, and

  3. there can be as many augmentation functions as you want, and

  4. there can be as many augmentations as you want.

It is a good convention to name the receiver this, but you are free to call it differently.

Also, augmentation functions can take variable-arity arguments, as in:

augment java.lang.String {

  function concatWith = |this, args...| {
    var result = this
    foreach(arg in args) {
      result = result + arg
    }
    return result
  }
}

# (...)
function varargs = -> "a": concatWith("b", "c", "d")

It should be noted that augmentations work with class hierarchies too. The following example adds an augmentation to java.util.Collection, which also adds it to concrete subclasses such as java.util.LinkedList:

augment java.util.Collection {
  function plop = |this| -> "plop!"
}

# (...)
function plop_in_a_list = -> java.util.LinkedList(): plop()

9.3. Augmentation scopes, reusable augmentations

By default, an augmentation is only visible from its defining module.

Augmentations are clear and explicit as they only affect the instances from which you have decided to make them visible.

It is advised to place reusable augmentations in separate module definitions. Then, a module that needs such augmentations can make them available through imports.

Suppose that you want to define augmentations for dealing with URLs from strings. You could define a string-url-augmentations.golo module source as follows:

module my.StringUrlAugmentations

import java.net

augment java.lang.String {

  function toURL = |this| -> URL(this)

  function httpGet = |this| {
    # Open the URL, get a connection, grab the body as a string, etc
    # (...)
  }

  # (...)
}

Then, a module willing to take advantage of those augmentations can simply import their defining module:

module my.App

import my.StringUrlAugmentations

function googPageBody = -> "http://www.google.com/": httpGet()
As a matter of style, we suggest that your module names end with Augmentations. Because importing a module imports all of its augmentation definitions, we suggest that you modularize them with fine taste (for what it means).

To allow building libraries of functions leveraging augmentations, the callstack is also looked up in order to find if a complying augmentation was applied to the function arguments. It is thus possible to create a function like:

module MyLib

function sayPlop = |o| {
  println(o: plop())
}

that can be applied on any object having a plop method, provided this is a native method or it is defined in an augmentation imported in the calling module.

9.4. Named augmentations

It is possible for augmentations to have a name. A named augmentation is a set of functions that can be applied to some classes or structures.

This can be seen as a kind of lightweight trait, or mixin, as found in Rust, Groovy or Scala.

Named augmentations are defined with the augmentation keyword.

As an example:

augmentation FooBar = {
  function foo = |this| -> "foo"
  function bar = |this, a| -> this: length() + a
}

augmentation Spamable = {
  function spam = |this| -> "spam"
}

A named augmentation is applied using the augment …​ with construct, as in

augment java.util.Collection with FooBar

augment MyStruct with Spamable

augment java.lang.String with FooBar, Spamable

When applying several named augmentations, they are used in the application order. For instance, if AugmentA and AugmentB define both the method meth, and we augment augment java.lang.String with AugmentA, AugmentB, then calling "": meth() will call AugmentA::meth.

Augmentation rules about scopes and reusability apply. So, if we create a module

module MyAugmentations

augmentation Searchable = {
  function search = |this, value| -> ...
}

augment java.util.Collection with Searchable

and import it, we can use the applied augmentation

import MyAugmentations

#...
list[1, 2, 3, 4]: search(2)

The augmentations defined in an other module can also be applied, provided they are fully qualified or the module is imported:

augment java.lang.String with MyAugmentations.Searchable

or

import MyAugmentations

augment java.lang.String with Searchable
If several imported modules define augmentations with the same name, the first imported one will be used.

The validity of the application is not checked at compile time. Thus augmenting without importing the coresponding module, as in:

augment java.lang.String with Searchable

will not raise an error, but trying to call search on a String will throw a java.lang.NoSuchMethodError: class java.lang.String::search at runtime.

As for every augmentation, no checks are made that the augmentation can be applied to the augmented class. For instance, augmenting java.lang.Number with the previous FooBar augmentation will raise java.lang.NoSuchMethodError: class java.lang.Integer::length at runtime when trying to call 1:bar(1). Calling 1:foo() will be OK however.

9.5. Augmentations Resolution Order

The augmentations resolution order is as follows:

  1. native java method (i.e. an augmentation can’t override a native java method),

  2. locally applied augmentations:

    1. simple augmentations: augment MyType { …​ },

    2. named augmentations: augmentation Foo = { …​ } and augment MyType with Foo in the current module. Multiple applications are searched in the application order,

    3. externally defined named augmentations with fully qualified name: augmentation Foo = { …​ } in module Augmentations, and augment MyType with Augmentations.Foo in the current module,

    4. named augmentation defined in an imported module: augmentation Foo = { …​ } in module Augmentations, and augment MyType with Foo in the current module that import Augmentations (imported module are searched in the importation order),

  3. augmentations applied in imported modules: using the same order than locally applied ones, in the importation order.

The first matching method found is used. It is thus possible to “override” an augmentation with a more higher priority one (in the sens of the previous order). Implicit modules are imported after explicit ones to allow to redefine standard augmentations.

Since importing a module imports all the applied augmentations, and given the somewhat complex resolution order when involving simple and named augmentations, being local, external or imported, and involving class hierarchies, knowing which method will be applied on a given type can be difficult. A good modularisation and a careful application are recommended.

9.6. Defining a fallback behavior

Users can augment a class with a fallback behavior to give a very last chance to a failed method dispacth.

augment java.lang.String {
  function fallback = |this, name, args...| {
    return "Dispatch failed for method: " + name + " on instance " + this + ", with args: " + args: asList(): join(" ")
  }
}

println("golo": notExistingMethod(1,2))
# Prints "Dispatch failed for method: notExistingMethod on instance golo, with args: [1, 2]"

9.7. Standard augmentations

Golo comes with a set of pre-defined augmentations over collections, strings, closures and more.

These augmentation do not require a special import, and they are defined in the gololang.StandardAugmentations module.

Here is an example:

let odd = [1, 2, 3, 4, 5]: filter(|n| -> (n % 2) == 0)

let m = map[]
println(m: getOrElse("foo", -> "bar"))

The full set of standard augmentations is documented in the generated golodoc (hint: look for doc/golodoc in the Golo distribution).

10. Structs

Golo allows the definition of simple structures using the struct keyword. They resemble structures in procedural languages such as C struct or Pascal records. They are useful to store data when the set of named entries is fixed.

10.1. Definition

Structures are defined at the module-level:

module sample

struct Person = { name, age, email }

function main = |args| {
  let p1 = Person("Mr Bean", 54, "bean@gmail.com")
  println(p1: name())
  let p2 = Person(): name("John"): age(32): email("john@b-root.com")
  println(p2: age())
}

When declaring a structure, it also defines two factory functions: one with no argument, and one with all arguments in their order of declaration in the struct statement. When not initialized, member values are null.

Each member yields a getter and a setter method: given a member a, the getter is method a() while the setter is method a(newValue). It should be noted that setter methods return the structure instance which makes it possible to chain calls as illustrated in the previous example while building p2.

10.2. JVM existence

Each struct is compiled to a self-contained JVM class.

Given:

module sample

struct Point = { x, y }

a class sample.types.Point is being generated.

It is important to note that:

  1. each struct class is final,

  2. each struct class inherits from gololang.GoloStruct,

  3. proper definitions of toString(), hashCode() and equals() are being provided.

10.3. toString() behavior

The toString() method is being overridden to provide a meaningful description of a structure content.

Given the following program:

module test

struct Point = { x, y }

function main = |args| {
  println(Point(1, 2))
}

running it prints the following console output:

struct Point{x=1, y=2}

10.4. Immutable structs

Structure instances are mutable by default. Golo generates a factory function with the Immutable prefix to directly build immutable instances:

module test

struct Point = { x, y }

function main = |args| {

  let p = ImmutablePoint(1, 2)
  println(p)

  try {
    # Fails! (p is immutable)
    p: x(100)
  } catch (expected) {
    println(expected: getMessage())
  }
}

10.5. Custom factories

Golo generates two factories for structures. One for the initial values of each member and a second one with no parameters:

module test

struct Point = { x, y }

function main = |args| {
  println(Point(1, 2))
  println(Point())
}

running it prints the following console output:

struct Point{x=1, y=2}
struct Point{x=null, y=null}
By default the no-argument factory sets every member to null

The Factories generated by Golo can be overloaded by custom ones:

module test

struct Point = { x, y }

function Point = -> test.types.Point(0,0)

function main = |args| {
  println(Point(1, 2))
  println(Point())
}

running it prints the following console output:

struct Point{x=1, y=2}
struct Point{x=0, y=0}
Immutable factories can be easily overloaded by returning a forzen copy.
module test

struct Point = { x, y }

function ImmutablePoint = |a,b| -> test.types.Point(a,b): frozenCopy()

function main = |args| {
  println(ImmutablePoint(1, 2): isFrozen()) # prints true
}

10.6. Copying

Instances of a structure provide copying methods:

  • copy() returns a shallow copy of the structure instance, and

  • frozenCopy() returns a read-only shallow copy.

Trying to invoke any setter methods on an instance obtained through frozenCopy() raises a java.lang.IllegalStateException.

The result of calling copy() on a frozen instance is a mutable copy, not a frozen copy.

10.7. equals() and hashCode() semantics

Golo structures honor the contract of Java objects regarding equality and hash codes.

By default, equals() and hashCode() are the ones of java.lang.Object. Indeed, structure members can be changed, so they cannot be used to compute stable values.

Nevertheless, structure instances returned by frozenCopy() have stable members, and members are being used.

Consider the following program:

module test

struct Point = { x, y }

function main = |args| {

  let p1 = Point(1, 2)
  let p2 = Point(1, 2)
  let p3 = p1: frozenCopy()
  let p4 = p1: frozenCopy()

  println("p1 == p2 " + (p1 == p2))
  println("p1 == p3 " + (p1 == p3))
  println("p3 == p4 " + (p3 == p4))

  println("#p1 " + p1: hashCode())
  println("#p2 " + p2: hashCode())
  println("#p3 " + p3: hashCode())
  println("#p4 " + p4: hashCode())
}

the console output is the following:

p1 == p2 false
p1 == p3 false
p3 == p4 true
#p1 1555845260
#p2 104739310
#p3 994
#p4 994
It is recommended that you use Immutable<name of struct>(…​) or frozenCopy() when you can, especially when storing values into collections.

10.8. Comparison semantics

Golo structures are comparable with structures of the same type, provided that their members are comparable pairwise. Two structure are compared by comparing their members lexicographically, that is pairwise in the order they are defined.

For instance, the following listing:

module test

struct Triplet = {x, y, z}

struct Other = {x, y, z}

function main = |args| {

  let t1 = Triplet(1, 2, 3)
  let t2 = Triplet(1, 3, 2)
  let o = Other(1, 2, 4)

  println(t1 < t2)
  println(t1: values() < o: values())
  println(t1 < o)
}

will output:

true
true
Exception in thread "main" java.lang.IllegalArgumentException: struct Triplet{x=1, y=2, z=3} and struct Other{x=1, y=2, z=4} can't be compared

even if Triplet and Other have the same members.

10.9. Helper methods

A number of helper methods are being generated:

  • members() returns a tuple of the member names,

  • values() returns a tuple with the current member values,

  • isFrozen() returns a boolean to check for frozen structure instances,

  • iterator() provides an iterator over a structure where each element is a tuple [member, value],

  • get(name) returns the value of a member by its name,

  • set(name, value) updates the value of a member by its name, and returns the same structure.

10.10. Private members

By default, all members in a struct can be accessed. It is possible to make some elements private by prefixing them with _, as in:

struct Foo = { a, _b, c }

# (...)

let foo = Foo(1, 2, 3)

In this case, _b is a private struct member. This means that foo: _b() and foo: _b(666) are valid calls only if made from:

  • a function from the declaring module, or

  • an augmentation defined in the declaring module.

Any call to, say, foo: _b() from another module will yield a NoSuchMethodError exception.

Private struct members also have the following impact:

  • they do not appear in members() and values() calls, and

  • they are not iterated through iterator()-provided iterators, and

  • they are being used like other members in equals() and hashCode(), and

  • they do not appear in toString() representations.

10.11. Augmenting structs

Structs provide a simple data model, especially with private members for encapsulation.

Augmenting structs is encouraged, as in:

module Plop

struct Point = { _id, x, y }

augment Plop.types.Point {

  function str = |this| -> "{id=" + this: _id() + ",x=" + this: x() + ",y=" + this: y() + "}"
}

When an augmentation on a struct is defined within the same module, then you can omit the full type name of the struct:

module Plop

struct Point = { _id, x, y }

augment Point {

  function str = |this| -> "{id=" + this: _id() + ",x=" + this: x() + ",y=" + this: y() + "}"
}

Again, it is important to note that augmentations can only access private struct members when they originate from the same module.

Don’t do this at home

Of course doing the following is a bad idea, with the concise augmentation taking over the fully-qualified one:

module Foo

struct Value = { v }

augment Foo.types.Value {

  function a = |this| -> "a"
}

# This will discard the previous augmentation...
augment Value {

  function b = |this| -> "a"
}

function check = {
  let v = Value(666)

  # Ok
  v: b()

  # Fails, the concise augmentation overrides the fully-qualifed one
  v: a()
}

11. Unions

Golo allows the definition of sum algebraic data types, also known as tagged union, as present in many functional languages: OCaml, Haskell, Rust, Scala to name a few. The dual algebraic data type, the product type is provided by struct and tuple.

11.1. Definition

Unions are defined at the module-level:

module sample

union Option = {
 Some = { value }
 None
}

function main = |args| {
  let aString = Option.Some("Hello")
  println(aString: value())

  let noString = Option.None()
  println(noString)
}

11.2. Usage example

Some well known usages of sum types are the following.

11.2.1. Enumerations

The plain old list of predefined values.

union Color = {
  RED
  GREEN
  BLUE
}

This use is similar to Java enum, with the same power since Golo union can be extended through augmentation.

11.2.2. Option type

The monadic type as found for instance in OCaml (Option), Haskell (Maybe) and many other languages (Rust, Scala, etc.)

union Option = {
  Some = {value}
  None
}

As illustrated here, and contrary to Java enum, each alternative value can have different fields. A union alternative type is in this respect similar to immutable struct.

11.2.3. Recursive data structures

The usual functional representation of linked lists:

union ConsList = {
  List = { head, tail }
  Empty
}

Binary trees:

union Tree = {
  Empty
  Leaf = { value }
  Node = { left, right }
}

11.3. JVM existence

A union type is compiled to an abstract JVM class. Each alternative value type is itself compiled to a final immutable JVM class extending the abstract class. The value classes are member classes of the abstract one.

Given:

module sample

union Option = {
  Some = { value }
  None
}

three classes are generated:

  1. an abstract class sample.types.Option,

  2. a concrete final immutable inner class sample.types.Option$Some extending the first one,

  3. a similar class sample.types.Option$None.

For your convenience, the abstract class provides factories static methods for each of the possible values, and you can’t instantiate values directly, since values without fields are actually singletons.

Note that proper definitions of toString(), hashCode() and equals() are provided. These definitions are similar to the ones defined for frozen struct.

union values with fields are similar to frozen struct, that is are immutable, have getters for fields and are compared by values. However, these types does not feature the same helper methods, and can’t have private members.

11.4. Special testing methods

Unions feature special methods to test for the exact type of a value, as well as members values if applicable. This allows to write readable tests, more specially using the match clause, to look like destructuring match in langages like OCaml, Haskell or Scala.

For instance, given a union defining a binary tree:

union Tree = {
  Node = {left, right}
  Leaf = {value}
  Empty
}

one can match a elt value using:

match {
  when elt: isEmpty() then // we have an empty value
  when elt: isLeaf(0) then // we have a leaf containing 0
  when elt: isLeaf()  then // we have a leaf (whatever the value)
  when elt: isNode(Empty(), Empty()) then // we have a node with empty children
  when elt: isNode(Leaf(42), Leaf(42)) then // we have a node whose both children contain 42
  when elt: isNode() then // we have a node, whatever the values
  otherwise // default case...
}

More precisely, each possible union value provides parameterless methods testing its exact type, named is<TypeName>. In the tree example, three methods are defined: isEmpty(), isLeaf() and isNode(). In addition to these methods, a method with parameters is defined for every alternative with members, here isLeaf(value) and isNode(left, right). The arguments are compared for equality to the members of the union value. For instance:

Leaf(0): isLeaf(0) # true
Leaf(42): isLeaf(0) # false

allowing readable test and match clauses.

A special singleton value is available to make these clauses even more readable: the Unknown value. This special singleton is considered equal to any other object (except null), and thus can be used in the parametrized test methods to ignore some members. For instance, to match a Node with only one child, one can use:

let _ = Unknown.get()

function dealWithTree = |elt| -> match {
  when elt: isNode(Empty(), _) or elt: isNode(_, Empty()) then ...
    // one of the children is Empty, whatever the other one
  otherwise ...
}

11.5. Augmenting unions

Since the union itself is a abstract class, and each possible value is a concrete class extending it, it is possible to augment the whole union, as in:

augment Option {
  function map = |this, func| -> match {
    when this: isNone() then this
    otherwise Option.Some(func(this: value()))
  }
}

or just a value, as in:

augment ConsList$Empty {
  function size = |this| -> 0
  function head = |this| -> null
  function tail = |this| -> this
}

augment ConsList$List {
  function size = |this| -> 1 + this: tail(): size()
}

12. Dynamic objects

Dynamic objects can have values and methods being added and removed dynamically at runtime. You can think of it as an enhancement over using hash maps and putting closures in them.

12.1. Creating dynamic objects

Creating a dynamic object is as simple as calling the DynamicObject function:

let foo = DynamicObject()

A dynamic object can also be tagged using an arbitrary value as its kind. To create a tagged dynamic object, simply use a value in the constructor:

let bar = DynamicObject("Bar")

Dynamic objects have the following reserved methods, that is, methods that you cannot override:

  • define(name, value) allows to define an object property, which can be either a value or a closure, and

  • get(name) gives the value or closure for a property name, or null if there is none, and

  • undefine(name) removes a property from the object, and

  • mixin(dynobj) mixes in all the properties of the dynamic object dynobj, and

  • copy() gives a copy of a dynamic object, and

  • freeze() locks an object, and calling define will raise an IllegalStateException, and

  • isFrozen() checks whether a dynamic object is frozen or not, and

  • properties() gives the set of entries in the dynamic object, and

  • hasMethod(name) checks if a method is defined or not in the dynamic object, and

  • invoker(name, type) which is mostly used by the Golo runtime internals, and

  • hasKind(value) tests if the dynamic object is tagged with this value, and

  • sameKind(other) tests if two dynamic objects have the same kind, and

  • fallback(handler) defines a fallback behavior for property invocation.

Moreover, a suitable toString method is provided, but you can override it by defining a toString method.

12.2. Defining values

Defining values also defines getter and setter methods, as illustrated by the next example:

let person = DynamicObject():
  define("name", "MrBean"):
  define("email", "mrbean@gmail.com")

# prints "Mr Bean"
println(person: name())

# prints "Mr Beanz"
person: name("Mr Beanz")
println(person: name())

Calling a setter method for a non-existent property defines it, hence the previous example can be rewritten as:

let person = DynamicObject(): name("MrBean"): email("mrbean@gmail.com")

# prints "Mr Bean"
println(person: name())

# prints "Mr Beanz"
person: name("Mr Beanz")
println(person: name())

12.3. Defining methods

Dynamic object methods are simply defined as closures. They must take the dynamic object object as their first argument, and we suggest that you call it this. You can then define as many parameters as you want.

Here is an example where we define a toString-style of method:

local function mrbean = -> DynamicObject():
  name("Mr Bean"):
  email("mrbean@gmail.com"):
  define("toString", |this| -> this: name() + " <" + this: email() + ">")

function main = |args| {

  let bean = mrbean()
  println(bean: toString())

  bean: email("mrbean@outlook.com")
  println(bean: toString())
}
You cannot overload methods, that is, providing methods with the same name but different signatures.

It is strongly recommended that you use define to create and update methods. Consider the following example:

let obj = DynamicObject():
  plop(|this| -> "Plop!")

Any call such as obj: plop() properly calls plop(). Because the dynamic object is fresh and new, the first call to plop creates a property since it is currently missing.

That being said, the following would fail:

obj: plop(|this| -> "Plop it up!")

Indeed, when the value of a dynamic object property is a function, it is understood to be a method, hence calling plop like it would be a setter method fails because there already exists a property that is a function, and it has a different signature. It needs to be updated as in:

obj: define('plop', |this| -> "Plop it up!")

As a rule of thumb, prefer named setters for values and define for methods. It is acceptable to have named definitions for methods if and only if a call happens after the object creation and before any call to mixin (remember that it injects properties from other objects, including methods).

12.4. Querying the properties

The properties() method returns a set of entries, as instances of java.util.Map.Entry. You can thus write code such as:

function dump = |obj| {
  foreach prop in obj: properties() {
    println(prop: key() + " -> " + prop: value())
  }
}

Because dynamic object entries mix both values and function references, do not forget that the predefined isClosure(obj) function can be useful to distinguish them.

12.5. Defining a fallback behavior

The fallback(handler) method let’s the user define a method that is invoked whenever the initial method dispatch fails. Here is an example of how to define a fallback.

Calling a setter method for a non-existent property defines it, thus the fallback is not applicable for setters.
let dynob = DynamicObject():
  fallback(|this, method, args...| {
    return "Dispatch failed for method: " + method + ", with args: " + args: asList(): join(" ")
  })

println(dynob: casperGetter())
println(dynob: casperMethod("foo", "bar"))
Dispatch failed for method: casperGetter, with args:
Dispatch failed for method: casperMethod, with args: foo bar

A delegate function is available to ease defining a fallback function that delegates on another dynamic object. For instance:

let t = DynamicObject("deleguee")
  : name("Zaphod")
  : define("sayHello", |this| -> "Hello, I'm " + this: name())

let s = DynamicObject("withFallback")
  : fallback(DynamicObject.delegate(t))

require(s: sayHello() == "Hello, I'm Zaphod", "error")

12.6. Kind of dynamic objects

The kind of a dynamic object can be any value. The more typical values are strings and unions (enumerations). This value is used by the toString() method to display a more specific representation of the object, and defaults to the string "DynamicObject". By using the two predefined methods hasKind(value) and sameKind(other), it is possible to test for the kind of a dynamic object. Note that the kind of a created object can’t be changed.

function Person = |name, age| -> DynamicObject("Person")
    : name(name)
    : age(age)
    : define("marry", |this, other| {
      require(this: sameKind(other), "Can only marry a person")
      this: spouse(other)
      other: spouse(this)
    })

function printAge = |obj| {
  if (obj: hasKind("Person")) {
    println(obj: age())
  } else {
    println("I have no age")
  }
}

13. Adapters

There is already much you can do while in Golo land using functions, closures, structs, augmentations and dynamic objects.

Yet, the JVM is a wider ecosystem and you will soon be tempted to integrate existing Java libraries into your code. Calling Java libraries from Golo is quite easy, but what happens when you need to subclass classes or provide objects that implement specific interfaces?

As you can easily guess, this is all what adapters are about: they allow the definition of objects at runtime that can extend and inherit Java types.

13.1. A simple example

Let us get started with a simple example of a web application based on the nice Spark micro-framework [1].

Spark requires route handlers to extend an abstract base class called spark.Route. The following code snippet does just that:

module sparky

import spark
import spark.Spark

function main = |args| {
  let conf = map[   (1)
    ["extends", "spark.Route"],   (2)
    ["implements", map[   (3)
      ["handle", |this, request, response| {  (4)
        return "Golo, world!"
      }]
    ]]
  ]
  let fabric = AdapterFabric()  (5)
  let routeMaker = fabric: maker(conf)  (6)
  let route = routeMaker: newInstance("/hello")   (7)
  get(route)  (8)
}
1 An adapter configuration is provided by a map object.
2 The extends key allows specifying the name of the parent class (java.lang.Object by default).
3 The implements provides a map of method implementations.
4 The implementation is given by a closure whose signature matches the parent class definition, and where the first argument is the receiver object that is going to be the adapter instance.
5 An adapter fabric provides context for creating adapters. It manages its own class loader.
6 An adapter maker creates instances based on a configuration.
7 The newInstance() method calls the right constructor based on the parent class constructors and provided argument types.
8 The spark.Spark.get() static is method is happy as we feed it a subclass of spark.Route.
Adapter objects implement the gololang.GoloAdapter marker interface, so you can do type checks on them a in: (foo oftype gololang.GoloAdapter.class).

13.2. Implementing interfaces

This is as easy as providing a java.lang.Iterable as part of the configuration:

let result = array[1, 2, 3]
let conf = map[
  ["interfaces", ["java.io.Serializable", "java.lang.Runnable"]],
  ["implements", map[
    ["run", |this| {
      for (var i = 0, i < result: length(), i = i + 1) {
        result: set(i, result: get(i) + 10)
      }
    }]
  ]]
]
let runner = AdapterFabric(): maker(conf): newInstance()
runner: run() (1)
1 As you may guess, this changes the result array values to [11, 12, 13].

13.3. Overrides

Implementations are great, but what happens if you need to call the parent class implementation of a method? In Java, you would use a super reference, but Golo does not provide that.

Instead, you can override methods, and have the parent class implementation given to you as a method handle parameter:

let conf = map[
  ["overrides", map[
    ["toString", |super, this| -> ">>> " + super(this)]
  ]]
]
println(AdapterFabric(): maker(conf): newInstance(): toString()) (1)
1 This prints something like: >>> $Golo$Adapter$0@12fc7ceb.
You can mix both implementations and overrides in an adapter configuration.

13.4. Star implementations and overrides

You can pass * as a name for implementations or overrides. In such cases, the provided closure become the dispatch targets for all methods that do not have an implementation or override. Note that providing both a star implementation and a star override is an error.

Let us see a concrete example:

let carbonCopy = list[] (1)
let conf = map[
  ["extends", "java.util.ArrayList"],
  ["overrides", map[
    ["*", |super, name, args| { (2)
      if name == "add" {
        if args: length() == 2 {
          carbonCopy: add(args: get(1))  (3)
        } else {
          carbonCopy: add(args: get(1), args: get(2)) (4)
        }
      }
      return super: spread(args)  (5)
    }
  ]]
]]
let list = AdapterFabric(): maker(conf): newInstance()
list: add("bar")
list: add(0, "foo")
list: add("baz")  (6)
1 We create an empty list, more on that later.
2 A star override takes 3 parameters: the parent class implementation, the method name and the arguments into an array (the element at index 0 is the receiver).
3 We copy into carbonCopy.
4 Same here, but we dispatch to a different method
5 We just call the parent class implementation of whatever method it is. Note that spread allows to dispatch a closure call with an array of arguments.
6 At this point carbonCopy contains ["foo", "bar", "baz"] (and so does list, too).

The case of star implementation is similar, except that the closure takes only 2 parameters: |name, args|.

13.5. Misc.

The AdapterFabric constructor can also take a class loader as a parameter. When none is provided, the current thread context class loader is being used as a parent for an AdapterFabric-internal classloader. There is also a static method withParentClassLoader(classloader) to obtain a fabric whose class loader is based on a provided parent.

As it is often the case for dynamic languages on the JVM, overloaded methods with the same name but different methods are painful. In such cases, we suggest that you take advantage of star-implementations or star-overrides as illustrated above on a ArrayList subclass where the 2 add(obj) and add(index, obj) methods are being intercepted.

Finally we do not encourage you to use adapters as part of Golo code outside of providing bridges to third-party APIs.

13.6. Adapters helper

This is another way to use the adapters. You can see that as a kind of DSL for the Golo adapters. Let’s see how to re-write the examples in the previous paragraph

13.6.1. A simple example

Let us get started (again) with a simple example of a web application based on the Spark micro-framework.

module sparky

import gololang.Adapters
import spark
import spark.Spark

function main = |args| {
  let sparkRouteAdapter = Adapter()   (1)
    : extends("spark.Route")   (2)
    : implements("handle", |this, request, response| {   (3)
        return "Golo, world!"
      })
  let route = sparkRouteAdapter: newInstance("/hello")  (4)
  get(route)  (5)

}
1 An adapter factory.
2 The extends method specifies the name of the parent class (java.lang.Object by default).
3 The implements method specifies the method implementations. The implementation is given by a closure whose signature matches the parent class definition, and where the first argument is the receiver object that is going to be the adapter instance.
4 The newInstance() method calls the right constructor based on the parent class constructors and provided argument types.
5 The spark.Spark.get() static is method is happy as we feed it a subclass of spark.Route.

13.6.2. Implementing interfaces

let result = array[1, 2, 3]
let conf = Adapter(): interfaces(["java.io.Serializable", "java.lang.Runnable"])
  : implements("run", |this| {
      for (var i = 0, i < result: length(), i = i + 1) {
        result: set(i, result: get(i) + 10)
      }
  })
let runner = conf: newInstance()
runner: run() (1)
1 As you may guess, this changes the result array values to [11, 12, 13].

13.6.3. Overrides

let conf = Adapter(): overrides("toString", |super, this| -> ">>> " + super(this))
println(conf: newInstance(): toString()) (1)
1 This prints something like: >>> $Golo$Adapter$0@12fc7ceb.

13.6.4. Star implementations and overrides

let carbonCopy = list[] (1)
let conf = Adapter(): extends("java.util.ArrayList")
  : overrides("*", |super, name, args| {
      if name == "add" {
        if args: length() == 2 {
          carbonCopy: add(args: get(1))
        } else {
          carbonCopy: add(args: get(1), args: get(2))
        }
      }
      return super: invoke(args)
  })
let list = conf: newInstance()
list: add("bar")
list: add(0, "foo")
list: add("baz")  (1)
1 At this point carbonCopy contains ["foo", "bar", "baz"] (and so does list, too).

14. Decorators

Golo features Python-like decorators.

14.1. Presentation

Decorators are similar in syntax and purpose to Java annotations. However, the concepts behind them are very different. Indeed, whereas Java annotations are compiler or VM directives, decorators are actually plain functions, more precisely higher order functions.

Higher order functions (HOF) are functions that process functions, i.e. that take a function as parameter, and may return a new function.

A decorator is thus a function that take the function to decorate as parameter, and return a new function, generally a wrapper that do some stuffs before or after calling the original function.

The name can remind the well known GoF Pattern, with good reason. This pattern describe a design that allow an object to be augmented by wrapping it in an other object with the same interface, delegating operations to the wrapped object. This is exactly what a decorator does here, the interface being "function" (more precisely a gololang.FunctionReference).

14.2. Principles and syntax

As in Python, and similarly to Java annotations, a decorator is used with a @ prefix before the function definition. As an example, the decorator deco1 only prints its name before returning the result unchanged

function deco1 = |fun| {
  return |args...| {
    return "deco1 + " + fun: invoke(args)
  }
}

It can be used as:

@deco1
function foo = |a| {
  return "foo: " + a
}

Here, calling println(foo(1)) will print deco1 + foo: 1.

To be the most generic, the function created by a decorator should be a variable arity function, and thus call the decorated function with invoke, such that it can be applied to any function, regardless of its arity, as in the previous example.

Indeed, suppose you what to a decorator dec (that does nothing) used like:

@dec
function add = |a,b| -> a + b

Such a decorator can be implemented as:

function dec = |func| -> |a, b| -> func(a, b)

But in that case, it will be applicable to two parameters functions only. On the other hand, you cannot do:

function dec = |func| -> |args...| -> func(args)

Indeed, this will throw an exception because func is not a variable arity function (just a reference on add function) and thus cannot take an array as parameter. In this case, the decorator have to invoke the original function like this:

function dec = |func| -> |args...| -> func(args: get(0), args: get(1))

which is equivalent to the first form, but is not generic. The more generic decorator is thus:

function dec = |func| -> |args...| -> func: invoke(args)

which can deal with any function.

As illustrated, the decorator is just a wrapper (closure) around the decorated function. The @ syntax is just syntactic sugar. Indeed, it can also be used as such:

function bar = |a| -> "bar: " + a

function main = |args| {
  println(deco1(^bar)(1))

  let decobar = deco1(^bar)
  println(decobar(1))

  println(deco1(|a| -> "bar: "+a)(1))
}

prints all deco1 + bar: 1.

Decorators can also be stacked. For instance:

function deco2 = |fun| {
  return |args...| {
    return "deco2 + " + fun: invoke(args)
  }
}

@deco2
@deco1
function baz = |a| -> "baz: " + a

println(baz(1)) will print deco2 + deco1 + baz: 1

This result can also be achieved by composing decorators, as in:

let deco3 = ^deco1: andThen(^deco2)

@deco3
function spam = |a| -> "spam: " + a

Again, println(spam(1)) will print deco2 + deco1 + spam: 1

Moreover, since decorator are just higher order functions, they can be closure on a first argument, i.e. parametrized decorators, as illustrated in the following listing:

module tests.LogDeco

function log = |msg| -> |fun| -> |args...| {
  println(msg)
  return fun: invoke(args)
}

@log("calling foo")
function foo = |a| {
  println("foo got a " + a)
}

@log("I'am a bar")
function bar = |a| -> 2*a

function main = |args| {
  foo("bar")
  println(bar(21))
}

will print

calling foo
foo got a bar
I'am a bar
42

Here, log create a closure on the message, and return the decorator function. Thus, log("hello") is a function that take a function as parameter, and return a new function printing the message (hello) before delegating to the inner function.

Again, since all of this are just functions, you can create shortcuts:

let sayHello = log("Hello")

@sayHello
function baz = -> "Goodbye"

A call to println(baz()) will print

Hello
Goodbye

The only requirement is that the effective decorator (the expression following the @) is eventually a HOF returning a closure on the decorated function. As an example, it can be as elaborated as:

function log = |msgBefore| -> |msgAfter| -> |func| -> |args...| {
  println(msgBefore)
  let res = func: invoke(args)
  println(msgAfter)
  return res
}

@log("enter foo")("exit foo")
function foo = |a| {
  println("foo: " + a)
}

where a call foo("bar") will print

enter foo
foo: bar
exit foo

and with

function logEnterExit = |name| -> log("# enter " + name)("# exit " + name)

@logEnterExit("bar")
function bar = { println("doing something...") }

calling bar() will print

# enter bar
doing something...
# exit bar

or even, without decorator syntax:

function main = |args| {
  let strange_use = log("hello")("goodbye")({println(":p")})
  strange_use()

  log("another")("use")(|a|{println(a)})("strange")
}

A last thing (but not the least), the function returned by the decorator can have a different arity than the original one:

function curry = |f| -> |a| -> |b| -> f(a, b)

@curry
function add = |a,b| -> a + b

function main = |args| {
  add(12)(30)
}

The @curry decorator transform the add function that takes two arguments, into a function that takes only one argument and returns a function that takes the second argument and finally return the result of the addition.

A decorator is applied only if the decorated function is called from Golo code. For example if you try to call a decorated Golo function from Java code it will not be the decorated function that will be called but the original one.
It is possible to create decorator and decorated functions in pure Java:
package decorators;

import gololang.annotations.DecoratedBy;
import gololang.FunctionReference;

public class Decorators {

  public static Object decorator(Object original) {
    FunctionReference reference = (FunctionReference) original;
    // do some transformations
    System.out.println("decorator!");
    return reference;
  }

  @DecoratedBy("decorator")
  public static int add(int a, int b) {
    return a + b;
  }

}

Let’s call this from Golo:

import decorators.Decorators

function main = |args| {
  println(add(10,32))
}

will print:

decorator!
42

Let’s now illustrate with some use cases and examples, with a presentation of some decorators of the standard module gololang.Decorators.

14.3. Use cases and examples

Use cases are at least the same as aspect oriented programming (AOP) and the Decorator design pattern, but your imagination is your limit. Some are presented here for illustration.

14.3.1. Logging

Logging is a classical example use case of AOP. See the Principles and syntax section for an example.

14.3.2. Pre/post conditions checking

Decorators can be used to check pre-conditions, that is conditions that must hold for arguments, and post-conditions, that is conditions that must hold for returned values, of a function.

Indeed, a decorated can execute code before delegating to the decorated function, of after the delegation.

The module gololang.Decorators provide two decorators and several utility functions to check pre and post conditions.

checkResult is a parametrized decorator taking a checker as parameter. It checks that the result of the decorated function is valid.

checkArguments is a variable arity function, taking as much checkers as the decorated function arguments. It checks that the arguments of the decorated function are valid according to the corresponding checker (1st argument checked by 1st checker, and so on).

A checker is a function that raises an exception if its argument is not valid (e.g. using require) or returns it unchanged, allowing checkers to be chained using the andThen method.

As an example, one can check that the arguments and result of a function are integers with:

let isInteger = |v| {
  require(v oftype Integer.class, v + "is not an Integer")
  return v
}

@checkResult(isInteger)
@checkArguments(isInteger, isInteger)
function add = |a, b| -> a + b

or that the argument is a positive integer:

let isPositive = |v| {
  require(v > 0, v + "is not > 0")
  return v
}

@checkArguments(isInteger: andThen(isPositive))
function inv = |v| -> 1.0 / v

Of course, again, you can take shortcuts:

let isPositiveInt = isInteger: andThen(isPositive)

@checkResult(isPositiveInt)
@checkArguments(isPositiveInt)
function double = |v| -> 2 * v

or even

let myCheck = checkArguments(isInteger: andThen(isPositive))

@myCheck
function inv = |v| -> 1.0 / v

@myCheck
function mul = |v| -> 10 * v

Several factory functions are available in gololang.Decorators to ease the creation of checkers:

  • any is a void checker that does nothing. It can used when you need to check only some arguments of a n-ary function.

  • asChecker is a factory that takes a boolean function and an error message and returns the corresponding checker. For instance:

let isPositive = asChecker(|v| -> v > 0, "is not positive")
  • isOfType is a factory function that returns a function checking types, e.g.

let isInteger = isOfType(Integer.class)

The full set of standard checkers is documented in the generated golodoc (hint: look for doc/golodoc in the Golo distribution).

14.3.3. Locking

As seen, decorator can be used to wrap a function call between checking operation, but also between a lock/unlock in a concurrent context:

import java.util.concurrent.locks

function withLock = |lock| -> |fun| -> |args...| {
  lock: lock()
  try {
    return fun: invoke(args)
  } finally {
    lock: unlock()
  }
}

let myLock = ReentrantLock()

@withLock(myLock)
function foo = |a, b| {
  return a + b
}

14.3.4. Memoization

Memoization is the optimization technique that stores the results of a expensive computation to return them directly on subsequent calls. It is quite easy, using decorators, to transform a function into a memoized one. The decorator creates a closure on a hashmap, and check the existence of the results before delegating to the decorated function, and storing the result in the hashmap if needed.

Such a decorator is provided in the gololang.Decorators module, presented here as an example:

function memoizer = {
  var cache = map[]
  return |fun| {
    return |args...| {
      let key = [fun: hashCode(), Tuple(args)]
      if (not cache: containsKey(key)) {
        cache: add(key, fun: invoke(args))
      }
      return cache: get(key)
    }
  }
}

The cache key is the decorated function and its call arguments, thus the decorator can be used for every module functions. It must however be put in a module-level state, since in the current implementation, the decoration is invoked at each call. For instance:

let memo = memoizer()

@memo
function fib = |n| {
  if n <= 1 {
    return n
  } else {
    return fib(n - 1) + fib(n - 2)
  }
}

@memo
function fact = |n| {
  if n == 0 {
    return 1
  } else {
    return n * fact(n - 1)
  }
}

14.3.5. Generic context

Decorators can be used to define a generic wrapper around a function, that extends the previous example (and can be used to implement most of them). This functionality is provided by the gololang.Decorators.withContext standard decorator. This decorator take a context, such as the one returned by gololang.Decorators.defaultContext function.

A context is an object with 4 defined methods:

  • entry, that takes and returns the function arguments. This method can be used to check arguments or apply transformation to them;

  • exit, that takes and returns the result of the function. This method can be used to check conditions or transform the result;

  • catcher, that deal with exceptions that occurs during function execution. It takes the exception as parameter;

  • finallizer, that is called in a finally clause after function execution.

The context returned by gololang.Decorators.defaultContext is a void one, that is entry and exit return their parameters unchanged, catcher rethrow the exception and finallizer does nothing.

The workflow of this decorator is as follow:

  1. the context entry method is called on the function arguments;

  2. the decorated function is called with arguments returned by entry;

    1. if an exception is raised, catcher is called with it as parameter;

    2. else the result is passed to exit and the returned value is returned

  3. the finallizer method is called.

Any of theses methods can modify the context internal state.

Here is an usage example:

module samples.ContextDecorator

import gololang.Decorators

let myContext = defaultContext():
  count(0):
  define("entry", |this, args| {
    this: count(this: count() + 1)
    println("hello:" + this: count())
    return args
  }):
  define("exit", |this, result| {
    require(result >= 3, "wrong value")
    println("goobye")
    return result
  }):
  define("catcher", |this, e| {
    println("Caught " + e)
    throw e
  }):
  define("finallizer", |this| {println("do some cleanup")})


@withContext(myContext)
function foo = |a, b| {
  println("Hard computation")
  return a + b
}

function main = |args| {
  println(foo(1,2))
  println("====")
  println(withContext(myContext)(|a| -> 2*a)(3))
  println("====")
  try {
    println(foo(1, 1))
  } catch (e) { }
}

which prints

hello:1
Hard computation
goobye
do some cleanup
3
====
hello:2
goobye
do some cleanup
6
====
hello:3
Hard computation
Caught java.lang.AssertionError: wrong value
do some cleanup

Since the context is here shared between decorations, the count attribute is incremented by each call to every decorated function, thus the output.

This generic decorator can be used to easily implement condition checking, logging, locking, and so on. It can be more interesting if you want to provide several functionalities, instead of stacking more specific decorators, since stacking, or decorator composition, adds indirection levels and deepen the call stack.

15. Banged function call

Golo uses invokedynamic [2] [3] to dynamically link at runtime an invocation instruction to the target code that will be effectively executed.

An invocation is done in three steps:

  • first, a computation is executed to find the target code,

  • then, the call site of the invocation is plugged to this target,

  • finally the target code is executed as if it had been linked at load time.

The first two phases are mostly executed once for a call site, according there’s no need to re-link the call site to his target code.

A function call marked with bang (!) is directly linked to the result returned by the target execution.

A banged invocation is executed like this:

  • first, a computation is executed to find the target code,

  • then the target code is executed,

  • finally, the call site of the invocation is plugged to a constant MethodHandle [4] which returns the target computation result as a constant value.

15.1. Principles and syntax

A function call marked with bang (!) will be called only once, the result is stored as a constant and will be directly returned for every subsequent call.

A function call can be marked with a bang like in the following example:

module sample

function take_a_while  = {
  # ... complex computation
  return 42
}


function main = |args| {

  foreach i in range(0, 100) {
   take_a_while!()
  }

}

In this example take_a_while is computed only once at the first call, and then this function returns directly the previously computed result as a constant for every subsequent call.

The ! notation can only be used on regular function calls. Indeed, since methods are context dependant (the object itself), it is not allowed to “bang” them. As a consequence, a function invocation using invoke of a function reference can’t use this feature.

Bang function call is a kind of memoization but regardless of the given parameters:

module sample

function hello = |name| {
  return "Hello " + name + "!"
}


function main = |args| {
  foreach name in ["Peter", "John", "James"] {
    println( hello!(name) # will always print 'Hello Peter!'
  }
}

In this example hello is executed at the first call with the parameter "Peter", then always returns "Hello Peter!", even when called with other values.

Functions having side effects should not be marked, since the computation is not done for subsequent calls, and thus the side effect can’t happen. In the same way, function that depends on an outside context are risky. Indeed, a change in the context won’t imply a change in the result any more. In other words, only pure functions should be marked with a !. No check is done by the language, use it at your own risk.

The result of a banged function call is constant within the same call place, but different for each call instructions.

module sample

function hello = |name| {
  return "Hello " + name + "!"
}

function main = |args| {
  println( hello!("Foo") ) # will print 'Hello Foo!'
  println( hello!("Bar") ) # will print 'Hello Bar!'
  foreach name in ["Peter", "John", "James"] {
   println( hello!(name) # will always print 'Hello Peter!'
  }
  foreach name in ["Peter", "John", "James"] {
   println( hello(name) # will print 'Hello Peter!', 'Hello John!', 'Hello James!'
  }
}

In the previous listing, the hello!(name) in the loop is considered the same call, and thus evaluated only on the first iteration. On the other hand, the previous calls with "Foo" and "Bar" are distinct, and therefore prints different results.

Anonymous function call and object constructor call can be banged too:

module sample

function closure = |x| {
  return |y| {
    return x * y
  }
}

function singleton = -> java.lang.Object!()

function main = |args| {

  foreach i in range(0, 100) {
    println( closure(i)!(i) ) # will always print 0
  }

  require(
    singleton(): hashCode() == singleton(): hashCode(),
    "Houston, ..."
  )
}

In this example closure(i)!(i) always return 0 because:

  • closure(i) returns a closure (|y| → x * y) with x as enclosed variable

  • closure(i) is computed for each value of i

  • the closure returned by closure(i) is called at the first iteration with 0 for x and y

  • for every subsequent call closure(i) is still computed but ignored because the anonymous call is replaced by the return of a constant value

The singleton function return a new java Object but the java.lang.Object is created with a banged constructor call, then the returned reference is constant.

15.2. Banged decorators

As explained in the decorators part the following identity function:

function decorator =  |func| -> |x| -> func(x)

@decorator
function identity = |x| -> x

is expanded to:

function decorator =  |func| -> |x| -> func(x)

function identity = |x| -> decorator(|x| -> x)(x)

A banged decorator declared with the @! syntax:

function decorator =  |func| -> |x| -> func(x)

@!decorator
function identity = |x| -> x

is expanded to:

function decorator =  |func| -> |x| -> func(x)

function identity = |x| -> decorator!(|x| -> x)(x)

As seen previously, the decorator function is called only the first time. For every subsequent call, the function reference returned by the decorator is not re-computed but directly used as a constant.

Parametrized decorators can be banged too:

function decorator =  |arg| -> |func| -> |x| -> func(x)

@!decorator(42)
function identity = |x| -> x

is expanded to:

function decorator =  |arg| -> |func| -> |x| -> func(x)

function identity = |x| -> decorator(42)!(|x| -> x)(x)
Considering the return of a banged call is constant, a common pitfall is to think that differents calls share the same "context" regardless where the call is located into the code.

As an example, consider two functions decorated with the same parametrized decorator:

@!deco("a")
function foo = |a| -> a

@!deco("b")
function bar = |b| -> b

These functions are expanded to

function foo = |a| -> deco("a")!(|a| -> a)(a)

function bar = |b| -> deco("b")!(|b| -> b)(b)

deco("a")!(|a| → a) return a function that we can name for the example func_a, and deco("b")!(|b| → b) return another function that we can name func_b.

Then, for every subsequent call of foo and bar, the executed code is somehow equivalent to:

function foo = |a| -> func_a(a)

function bar = |b| -> func_b(b)

func_a and func_b are now constant but different because they are not from the same "banged call instruction".

Performances can considerably increase with banged decorators, since the decorator function is no more called for each decorated function call. On the other hand, the decorator function has to be pure (without side-effects) and his parameters stable.

16. Dynamic code evaluation

Golo provides facilities for dynamically evaluating code from strings in the form of the gololang.EvaluationEnvironment class. It provides an API that is useful both when used from Golo code, or when used from a polyglot JVM application that embeds Golo.

16.1. Loading a module

The code of a complete module can be evaluated by the asModule method:

let env = gololang.EvaluationEnvironment()
let code =
"""
module foo

function a = -> "a!"
function b = -> "b!"
"""
let mod = env: asModule(code)
let a = fun("a", mod)
let b = fun("b", mod)
println(a())
println(b())

It is important to note that an EvaluationEnvironment instance has a GoloClassloader, and that attempting to evaluate module code with the same module declaration will cause an error. Indeed, a class loader cannot load classes with the same name twice.

16.2. Anonymous modules

The anonymousModule method is similar to asModule, except that the code to evaluate is free of module declaration:

let env = gololang.EvaluationEnvironment()
let code =
"""
function a = -> "a!"
function b = -> "b!"
"""
let mod = env: anonymousModule(code)
let a = fun("a", mod)
let b = fun("b", mod)
println(a())
println(b())

The modules that get evaluated through anonymousModule have unique names, hence this method is suitable in cases where the same code is to be re-evaluated several times.

16.3. Functions

The asFunction and def methods evaluate function code. Here is how asFunction can be used:

let env = gololang.EvaluationEnvironment()
let code = "return (a + b) * 2"
let f = env: asFunction(code, "a", "b")
println(f(10, 20))

It evaluates straight code as the body of a function. Note that imports can be used to specify import statements to be available while evaluation the code:

env:
  imports("java.util.LinkedList", "java.util.HashMap"):
  asFunction("""let l = LinkedList()
let m = HashMap()""")

The def method is similar, except that it has the parameters definition in the code to evaluate:

let env = gololang.EvaluationEnvironment()
let code = "|a, b| -> (a + b) * 2"
let f = env: def(code)
println(f(10, 20))

16.4. Running code

The first form of run method works as follows:

let env = gololang.EvaluationEnvironment()
let code = """println(">>> run")
foreach i in range(0, 3) {
  println("w00t")
}
return 666"""
println(env: run(code)) # => "w00t"x3 and "666"

The second form allows passing parameter values in a map:

let env = gololang.EvaluationEnvironment()
let code = """println(">>> run_map")
println(a)
println(b)
"""
let values = java.util.TreeMap(): add("a", 1): add("b", 2)
env: run(code, values)

It is important not to abuse run, as each invocation triggers the generation of a one-shot class. If the same code is to be run several times, we suggest that you take advantage of either def or asFunction.

17. Concurrency with workers

Concurrency is hard. Fortunately for us the java.util.concurrent packages bring useful abstractions, data types and execution mechanisms to get concurrency "a little bit better".

Golo doesn’t provide a equivalent to the synchronized keyword of Java. This is on-purpose: when facing concurrency, we advise you to just use whatever is in java.util.concurrent.

That being said we provide a simple abstraction for concurrent executions in the form of workers. They pretty much resemble JavaScript web workers or isolates in Dart, albeit they do not really isolate the workers data space.

17.1. The big picture

A worker is simply a Golo function that can be executed concurrently. You can pass messages to a worker, and they are eventually received and handled by their target worker. In other words, workers react to messages in an asynchronous fashion.

Communications between a worker and some client code happens through ports. A port is simply an object that is responsible for dispatching a message to its worker.

Ports are obtained by spawning a worker function from a worker environment. Internally, a worker environment manages a java.util.concurrent executor, which means that you do not have to deal with thread management.

17.2. Worker environments

Worker environments are defined in the gololang.concurrent.workers.WorkerEnvironment class / module.

You can directly pass an instance of java.util.concurrent.ExecutorService to its constructor, or you may go through its builder object and call either of the following static methods:

  • withCachedThreadPool() uses a cached thread pool,

  • withFixedThreadPool(size) uses a fixed number of threads in a pool,

  • withFixedThreadPool() uses a pool with 1 thread per processor core,

  • withSingleThreadExecutor() uses a single executor thread.

In most scenarios withCachedThreadPool() is a safe choice, but as usual, your mileage varies. If you have many concurrent tasks to perform and they are not IO-bound, then withFixedThreadPool() is probably a better option. You should always measure, and remember that you can always pass a fine-tuned executor to the WorkerEnvironment() constructor.

Worker environments also provide delegate methods to their internal executor. It is important to call shutdown() to close the workers environment and release the threads pool. You can also call the awaitTermination, isShutdown and isTerminated methods whose semantics are exactly those of java.util.concurrent.ExecutorService.

17.3. Spawning a worker and passing messages

Worker functions take a single parameter which is the message to be received. To obtain a port, you need to call the spawn(target) function of a worker environment, as in:

let env = WorkerEnvironment.builder(): withFixedThreadPool()
let port = env: spawn(|message| -> println(">>> " + message))

A port provides a send(message) method:

port: send("hello"): send("world")

Messages are being put in a queue, and eventually dispatched to the function that we spawned.

17.4. A complete and useless example

To better understand how workers can be used, here is a (fairly useless) example:

module SampleWithWorkers

import java.lang.Thread
import java.util.concurrent
import gololang.concurrent.workers.WorkerEnvironment

local function pusher = |queue, message| -> queue: offer(message) (3)

local function generator = |port, message| { (1)
  foreach i in range(0, 100) {
    port: send(message)                      (2)
  }
}

function main = |args| {

  let env = WorkerEnvironment.builder(): withFixedThreadPool()
  let queue = ConcurrentLinkedQueue()

  let pusherPort = env: spawn(^pusher: bindTo(queue))
  let generatorPort = env: spawn(^generator: bindTo(pusherPort))

  let finishPort = env: spawn(|any| -> env: shutdown()) (5)

  foreach i in range(0, 10) {
    generatorPort: send("[" + i + "]")
  }
  Thread.sleep(2000_L)
  finishPort: send("Die!") (4)

  env: awaitTermination(2000)
  println(queue: reduce("", |acc, next| -> acc + " " + next))
}

In this example, we spawn 3 workers:

1 the first repeats a message 100 times,
2 …​forwarding them to another one,
3 …​that ultimately pushes them to a concurrent queue.
4 A message is sent to a final worker,
5 …​that shuts the workers environment down.

As an aside, the example illustrates that worker functions may take further dependencies as arguments. The pusher function takes a queue target and generator needs a port.

You can satisfy dependencies by pre-binding function arguments, all you need is to make sure that each function passed to spawn only expects a single message as its argument, as in:

  • ^pusher: bindTo(queue), and

  • ^generator: bindTo(pusherPort), and

  • env: spawn(|any| → env: shutdown()) where the worker function is defined as a closure, and implicitly captures its env dependency from the surrounding context.

18. Golo template engine

Golo comes with a built-in template engine that is reminiscent of Java Server Pages or Ruby ERB. It compiles template text into Golo functions.

18.1. Example

Consider the following example.

let template = """
<%@params posts %>
<!DOCTYPE html>
<html>
  <head>
    <title>Golo Chat</title>
  </head>
  <body>
  <form action="/" method="post">
    <input type="text" name="msg">
    <input type="submit" value="Send">
  </form>
  <div>
    <h3>Last posts</h3>
    <% foreach post in posts { %>
      <div>
        <%= post %>
      </div>
    <% } %>
  </div>
  </body>
</html>
"""

This multi-line string has a Golo template. It can be compiled into a function as follows:

let tpl = gololang.TemplateEngine(): compile(template)
println(tpl(someDataModel: posts()))

18.2. Directives

As you may have guess from the previous example:

  • Golo code snippets are placed in <% %> blocks, and

  • expressions can output values using <%= %>, and

  • <%@import foo.bar.Baz %> causes foo.bar.Baz to be imported, and

  • <%@params foo, bar, baz %> causes the template function to have 3 parameters, i.e., it is a |foo, bar, baz| { …​ } function.

When no <%@params …​ %> exists, the function is assumed to have a single params parameter.

The template engine is a simple one and makes no verification either on the templates or the resulting Golo source code. The compile method may throw a GoloCompilation exception though, and you can query the exception getSourceCode() and getProblems() methods to obtain more details.

19. Documenting Golo code

Of course you can document your code using comments (#), but who reads source code?

19.1. Documentation blocks

Golo provides a support for documentation blocks on modules, functions, augmentations, structs and unions, as well as fields. Blocks are delimited by ---- and contain free-form Markdown [5] text.

Here is a quick example:

----
This is a *nice* module that does a bunch of useless things.

See more at [our website](http://www.typeunsafe.org).
----
module Hello

----
Adds 2 elements, which is quite surprising given the name.

* `x` is the first argument,
* `y` is the second argument.

The following snipped prints `3`:

    let result = adder(1, 2)
    println(result)

Impressive!
----
function adder = |x, y| -> x + y

Sections can be added in the documentation using the normal markdown syntax. The level of the titles is adapted to the generated documentation. For instance:

----
Encode a linked list as cons cells.

# Examples

A list is constructed from cons

    let myList = Cons(1, Cons(2, Cons(3, Empty())))

----
union List = {
  ----
  The empty list
  ----
  Empty

  ----
  A cell in the list
  ----
  Cons = {
    ----
    The head of the list
    ----
    head,

    ----
    The tail of the list
    ----
    tail
  }
}

The first sentence of a module documentation is displayed in module indexes.

19.2. Package documentation

Packages does not exists per se in Golo, but are represented in the form of module qualified names. However, it is common practice to group the modules of the same namespace into a common directory. There exists several ways to document such packages. The first is to create an empty golo module named after the package, containing the documentation. This file can have any name and be in any directory. For instance, given several modules pkg.MyModule and pkg.OtherModule, one can document the pkg package by creating a module containing:

----
Here goes the package documentation
----
module pkg

No class will be compiled from this module, only a documentation page.

The other way to document the pkg package, assuming that both modules are in src/pkg/MyModule.golo and src/pkg/OtherModule.golo respectively, is to create pure markdown file, containing the documentation for the package. This file must be named either src/pkg/README.md, src/pkg/package.md or src/pkg.md. If a golo file corresponding to the package exists, these files are ignored.

If several candidates are found, only the first one is used, and a warning is printed. It can be disabled by setting the golo.warnings.doc.multiple-package-desc system property to false.

19.3. Rendering documentation

The golo doc command can render documentation in html (the default) or markdown format:

$ golo doc --output target/documentation src/**/*.golo

In addition, golo doc can also produce ctags tags file, to be used by editors such as Vim or emacs. In this mode, the special output target - can be used to print the tags on standard output, which is needed by some editors or extensions.

Please consult golo --usage doc for more details.

19.4. Alignment

It is sometimes necessary to indent documentation blocks to match the surrounding code format. Documentation blocks erase indentation based on the indentation level of the opening block:

----
The most useful augmentation *ever*.
----
augment java.lang.String {

  ----
  Creates a URL from a string, as in: `let url = "http://foo.bar/plop": toURL()`.
  ----
  function toURL = |this| -> java.net.URL(this)
}

When generating documentation from the code above, the documentation block of the toURL function is unindented of 2 spaces.

20. Misc. modules

Not everything fits into the main documentation. We encourage you to also look at the javadocs and golodocs.

The next subsections provide summaries of misc. modules found as part of Golo.

20.1. Standard augmentations (gololang.StandardAugmentations)

This Golo module provides standard augmentations for various classes of the Java standard classes and Golo types. It does not have to be imported explicitely.

Here are a few examples.

Java collections can be have functional methods:

println(list[1, 2, 3, 4]: filter(|n| -> (n % 2) == 0))
println(list[1, 2, 3]: map(|n| -> n * 10))

Insert a map entry only if the key is not present, and get a default value if an entry is missing:

map: putIfAbsent(key, -> expensiveOperation())
map: getOrElse(key, "n/a")

Repeat an operation many times:

3: times(-> println("Hey!")
3: times(|i| -> println(i))

20.2. JSON support (gololang.JSON)

Golo includes the JSON Simple library to provide JSON support.

While json-simple only supports encoding from lists and maps, this API brings support for sets, arrays, Golo tuples, dynamic objects and structs.

Given a simple data structure, we can obtain a JSON representation:

let data = map[
  ["name", "Somebody"],
  ["age", 69],
  ["friends", list[
    "Mr Bean", "John B", "Larry"
  ]]
]
let asText = JSON.stringify(data)

Given some JSON as text, we can get back a data structure:

let data = JSON.parse(text)
println(data: get("name"))

The gololang.JSON module also provides helpers for JSON serialization and deserialization with both dynamic objects and structs.

20.3. Scala-like dynamic variable (gololang.DynamicVariable)

Golo has a DynamicVariable type that mimics the eponymous class from the Scala standard library.

A dynamic variable has inheritable thread-local semantics: updates to its value are confined to the current thread and its future child threads.

Given the following code:

let dyn = DynamicVariable("Foo")
println(dyn: value())

let t1 = Thread({
  dyn: withValue(666, {
    println(dyn: value())
  })
})

let t2 = Thread({
  dyn: withValue(69, {
    println(dyn: value())
  })
})

t1: start()
t2: start()
t1: join()
t2: join()
println(dyn: value())

one gets an output similar to:

Foo
69
666
Foo

with the 69 and 666 swapping order over runs.

20.4. Observable references (gololang.Observable)

An observable value notifies observers of updates in a thread-safe manner. An observable can also be constructed from another observable using the map and filter combinators:

let foo = Observable("Foo")
foo: onChange(|v| -> println("foo = " + v))

let mapped = foo: map(|v| -> v + "!")
mapped: onChange(|v| -> println("mapped = " + v))

foo: set("69")

This yields the following output:

foo = 69
mapped = 69!

20.5. Asynchronous programming helpers (gololang.Async)

This module offers asynchronous programming helpers, especially execution context agnostic promises and futures. The provided APIs are orthogonal to the execution strategy: it is up to you to execute code from the same thread, from a separate thread, or by pushing new tasks to a service executor.

Here is an example:

module samples.Concurrency

import java.util.concurrent
import gololang.Async

local function fib = |n| {
  if n <= 1 {
    return n
  } else {
    return fib(n - 1) + fib(n - 2)
  }
}

function main = |args| {
  let executor = Executors.newFixedThreadPool(2)
  let results = [30, 34, 35, 38, 39, 40, 41, 42]:
    map(|n| -> executor: enqueue(-> fib(n)):
      map(|res| -> [n, res]))
  reduce(results, "", |acc, next| -> acc + next: get(0) + " -> " + next: get(1) + "\n"):
    onSet(|s| -> println("Results:\n" + s)):
    onFail(|e| -> e: printStackTrace())
  executor: shutdown()
  executor: awaitTermination(120_L, TimeUnit.SECONDS())
}

This example takes advantages of an executor augmentation and composable promises and futures to compute Fibonacci numbers.

20.6. Lazy lists (gololang.lazylist)

This module defines a lazy list structure, as well as some utilities to work with it.

A lazy list behaves like an immutable linked list whose elements are evaluated only when needed, as can be found in Haskell for example.

The next element in the list (the tail) is represented by a closure. The generated value is cached so that the closure representing the next element is evaluated only once.

This is very useful when using higher order function such as map. Mapping a long lazy list with a function and using only the 3 first elements will only apply the function to these elements, as opposed to regular lists.

Since the tail closure will be called at most once, and we can’t guarantee when, or even if, it will be called, this closure must be a pure, side-effect free, function.

Lazy lists can also be used to create infinite lists, also known as generators (or anamorphisms).

Lastly, they allow for elegant recursive implementations of several classical algorithms.

For instance, one can create a infinite lazy list containing integers as:

function count = |start| -> cons(start, -> count(start + 1_L))
function count = -> count(0_L)

To construct a infinite list of all even multiples of 3, one can then use:

let l = count(): map(|x| -> 3 * x): filter(|x| -> (x % 2) == 0)

The cons function returns a new lazy list whose head is its first argument, and the tail its second.

A lazy list implement the Collection, interface, while remaining lazy. It is thus possible to use it in imperative style with a foreach construct, or recursively using head and tail. On the other hand, functions or methods like equals, size or contains are not very efficients, since they must evaluate the whole list, and thus negate the laziness. They are here for completeness and compatibility with the regular lists interface, but you should avoid such methods.

20.7. Console ANSI codes (gololang.AnsiCodes)

The gololang.AnsiCodes modules offers a set of functions to work with ANSI codes.

The following would print Hello world! in blinking yellow text:

import gololang.AnsiCodes

# (...)

function hello = {
  blink()
  fg_yellow()
  println("Hello world!")
  reset()
}
ANSI codes support varies from terminal and operating system capacities. Microsoft Windows does not support these codes without a 3rd-party driver. You may use the likelySupported() function to test if the host operating system is likely to support ANSI codes.

20.8. Functional errors (gololang.Errors)

The gololang.Errors module offers types, augmentations and decorators to deal with errors in a more functional way. This is similar for instance to Haskell Maybe and Either or Rust Option and Result.

20.8.1. Option

This is just an augmentation of the java java.util.Optional class together with factory functions and decorators. The added methods allows to better chain optional results and improve matching.

This is particularly useful to chain and compose functions that can return no result. Instead of returning null, a None() value can be returned. Such functions can then be chained using the andThen method. The option decorator can be used to transform a regular function into a function returning an Option.

For instance, given:

function foo = |arg| {
  # can return an integer, null or even throw an exception
}

function bar = -> 42

function plus2 = |x| -> x + 2
function mult2 = |x| -> x * 2

code such as:

var r
try {
  r = foo(x)
  if r is null {
    r = bar()
  } else {
    r = mult2(plus2(r))
  }
} catch (e) {
 r = bar()
}

can be rewritten:

let optionalFoo = option(foo)

r = optionalFoo(x): andThen(^plus2): either(^mult2, ^bar)

Of course, Optional methods such as flatMap and orElseGet can also be used:

@option
function safeGetter = |aMap, aKey| -> aMap: get(aKey)

let m = map[["a", 2], ["answer", 12]]

# (19 + 2) * 2 = 42
safeGetter(m, "answer"): map(^plus2): map(^mult2): orElseGet(^bar)

# get null, option returns None, bar gives 42
safeGetter(m, "plop"): map(^plus2): map(^mult2): orElseGet(^bar)

# null pointer exception, option returns None, bar gives 42
safeGetter(null, "answer"): map(^plus2): map(^mult2): orElseGet(^bar)

See the gololang.Errors module documentation for a full description of the added methods.

20.8.2. Result

Result is a similar object, but it keep the errors, meaning that a result can be empty (similar to None), containing an error (a Throwable) or a result. It can be used in a way very similar to Optional, but gives more control on the behavior.

The result decorator is the equivalent to option. The trying higher order function takes an anonymous block, executes it and returns a corresponding Result.

See the gololang.Errors module documentation and the javadoc for the gololang.error.Result class for more details.

As a bonus, Result objects can be destructured into the error and the value. For instance:

@result
function foo = {
  # can throw an exception, return null or a plain value
}

let e, v = foo()

let err, val = trying({
  # statements sequence than can throw an exception
  ...
  return somevalue
})

The error is the left value, the correct one the right (mnemonic: “right” also means “correct”). This allows to deal with error in the same way as Go does for instance.

The decorators nullify and raising are the duals of option or result

21. Common pitfalls

Discovering a new programming language is fun. Yet, we all make mistakes in the beginning, as we idiomatically repeat habits from other languages.

Because Golo works closely with the Java programming language, it is likely that Java programmers will make some of the following mistakes early on.

21.1. new

Golo does not have a new operator for allocating objects. Instead, one should just call a constructor as a function:

# Good
let foo = java.util.LinkedList()

# Compilation fails
let foo = new java.util.LinkedList()

21.2. Imports

Golo does not have star imports like in Java. Imports are only used at runtime as Golo tries to resolve names of types, functions, and so on.

You must think of import statements as a notational shortcut, nothing else. Golo tries to resolve a name as-is, then tries to complete with every import until a match is found.

import java.util
import java.util.concurrent.AtomicInteger

# (...)

# Direct resolution at runtime
let foo = java.util.LinkedList()

# Resolution with the 1st import
let foo = LinkedList()

# Resolution with the 2nd import
let foo = AtomicInteger(666)

21.3. Method invocations

Keep in mind that instance methods are invoked using the : operator, not with dots (.) like in many languages.

This is a common mistake!

# Calls toString() on foo
foo: toString()

# Looks for a function toString() in module foo
foo.toString()

21.4. match is not a closure

One thing to keep in mind is that match returns a value, and that it is not a closure unless you want it to.

let foo = match {
  case plop then 1
  case ploped then 2
  otherwise -1
}

# Ok
println(foo)

# Bad! foo is an integer!
println(foo("abc"))

21.5. Shebang scans sub-folders

When running shebang scripts, the sub-folders are being scanned for .jar and .golo files. This is useful for automatically:

  1. putting all third-party libraries into the classpath, and

  2. dynamically compiling and loading other Golo source files.

Be aware that this may lead to surprising errors if you run code from, say, a clone of the Golo source code repository since it contains duplicated type and module definitions, as well as files from the test suite that have errors on purpose.


1. Spark micro-framework
2. Oracle Java Magazine 2013-01-02
3. Oracle Java Magazine 2013-05-06
4. Constant MethodHandle
5. Markdown text