Golo, Think different
What is Golo? Golo is a lightweight dynamic language for the JVM. Yes, again! But a simple one!
Golo is build with invokedynamic. Golo is easy to use and even easy to modify (it will be the subject of a future article).
It was invented by Julien Ponge (the well known @jponge) the @TypeUnsafe Boss, but also a talented researcher at Dynamid.
Golo is a proof of Dynamid invokedynamic expertise and a powerfull tool to work with dynamic middlewares. To my mind, Golo is is also a great way to prototype your idea quickly using all the possibilities of the Java ecosystem. Indeed, Golo is born to “play” with Java. Golo simplify Java and help you to create nice DSL. You can think to Golo as syntactic sugar for Java.
Today, we’ll take a quick tour of Golo to learn basis.
Install Golo
You have to download Golo here : http://golo-lang.org/download/ and define environment variables:
GOLO_HOME=/where_you_have_unzip_golo_distribution/golo-0-preview12-SNAPSHOT;
export GOLO_HOME
export PATH=$PATH:$GOLO_HOME/bin
And now some code snippets
Golo is so simple that you can learn it only reading source code samples ;)
Functions and closures/lambda
Create a main.golo
file :
module demo
function hello = |who| {
println("Hello " + who)
}
function main = |args| {
let hi = |who| -> println("Hi " + who) # this is a closure
hi("John")
hello("Bob")
["John", "Jane", "Bob"]: each(|someone|{
hello(someone)
})
}
Run it : golo golo --files main.golo
Use and Augment Java
Create a jar file from this source java code :
package acme;
import java.lang.String;
import java.lang.System;
public class Toon {
public String name;
public Toon(String name) {
this.name = name;
}
public void hello() {
System.out.println("Hello, i'm " + this.name);
}
public static Toon getInstance(String value) {
return new Toon(value);
}
}
# Use Toon class with Golo
module demo
import acme
function main = |args| {
let buster = Toon("Buster") # new
println(buster: name()) # property (getter)
buster: name("BUSTER") # setter
buster: hello() # instance method
let babs = Toon.getInstance("Babs") # static method
println(babs: name())
}
Run it : golo golo --classpath jars/*.jar --files main.golo
(my jar file is in the jars
directory)
Remarks: please note the :
notation for calling instance method and .
notation for calling the class method.
# Add abilities to Toon class with Golo
With the augment
keyword you can add method to Java types (custom types as Toon
but even core Java types as String
, LinkedList
, …) :
module demo
import acme
augment acme.Toon {
# add "french" method
function salut = |this| {
println("Salut, je suis " + this: name())
}
}
function main = |args| {
let babs = Toon("Babs")
babs: salut() # print "Salut, je suis Babs"
}
No Class with Golo, but we have some very powerful elements of languages
# The structure
module demo_structure
struct human = {
firstName, lastName
}
function main = |args| {
let bob = human("Bob", "Morane")
let john = human(): firstName("John"): lastName("Doe")
println(
bob: firstName() + " " + bob: lastName()
)
println(
john: firstName() + " " + john: lastName()
)
}
And you can augment structures too!:
module demo_structure
struct human = {
firstName, lastName
}
augment human {
function hello = |this| ->
println("Hello " + this: firstName() + " " + this: lastName())
}
function main = |args| {
let bob = human("bob", "morane")
bob: hello()
}
# The DynamicObject
DynamicObject is a very flexible structure of Golo language which advantageously replaces the classes, with a touch of functional programming (no troll!) :
function main = |args| {
let clarkKent = DynamicObject()
: firstName("Clark")
: define("toString", |this| -> "firstName : " + this: firstName())
println(clarkKent: toString())
clarkKent: lastName("Kent")
: define("toString", |this| ->
"firstName : " + this: firstName() +
" lastName : " + this: lastName()
)
println(clarkKent: toString())
}
# # DynamicObject and mixin
There is no inheritance, but you can mixin DynamicObjects:
module demo_dynamic
function main = |args| {
let clarkKent = DynamicObject()
: firstName("Clark"): lastName("Kent")
let superMan = DynamicObject(): mixin(clarkKent)
superMan: heroName("SuperMan")
: power("flying")
: define("toString", |this| -> "I'm " +
this: firstName() + " " +
this: lastName() + " alias " +
this: heroName() + ", i'm " +
this: power()
)
println(superMan: toString())
}
# # Chaining pattern with DynamicObjects
It’s very usefull to create some DSL:
module demo_dynamic
function main = |args| {
let somebody = DynamicObject()
: define("who", |this, name| {
println("My name is " + name)
return this
})
: define("hero", |this, name| {
println("I am " + name)
return this
})
: define("power", |this, power| {
println("I've got a power: " + power)
return this
})
somebody: who("Tony Stark"): hero("IronMan"): power("flying")
somebody: hero("IronMan"): power("flying"): who("Tony Stark")
}
Golo plays with Java (again) with the dynamic adapters
Remember our Toon
class, you can create an adapter of acme.Toon
and re implement the hello()
method:
module demo
import acme
function main = |args| {
let toonDefinition = map[
["extends", "acme.Toon"],
["implements", map[
["hello", |this| {
println("Hello, i'm " + this: name())
}]
]]
]
let buster = AdapterFabric(): maker(toonDefinition)
: newInstance("Buster Bunny")
buster: hello()
}
Remarks: i use extends
, but you can use interfaces
too (if you’ve got an interface), see documentation: http://golo-lang.org/documentation/next/# _implementing_interfaces.
You can inject code before and after method thanks overrides
and super
:
module demo
import acme
function main = |args| {
let toonDefinition = map[
["extends", "acme.Toon"],
["overrides", map[
["hello", |super, this| {
println("Before ...")
super(this)
println("... After")
}]
]]
]
let buster = AdapterFabric(): maker(toonDefinition)
: newInstance("Buster Bunny")
buster: hello()
}
Remarks: dynamic adapters are very useful for deal with java frameworks, see example with SparkJava here: http://golo-lang.org/documentation/next/# _a_simple_example.
Draft of a web DSL
Actually, i’m working on a web framework with Golo thanks all these language structures. here’s what it will look like:
appRouter: add([
get("/hello/{name}") (|http| {
http: text(http: parameters(): get("name")): close()
})
, get("/about") (|http| {
http: html("<h1>Hello</h1><h2>World</h2><h3>!!!</h3>")
: close()
})
, get("/infos") (|http| {
http: allowCORS("*", "*", "*")
http: json(
JSON. stringify(DynamicObject()
: firstName("Bob")
: lastName("Morane"))
): close()
})
, post("/users") (|http|{
let data = http: request(): getQuery()
http: jsonize(map[
["firstName", data: get("firstName")]
]): status(201): close()
})
])
And soon we’ll able to write something like this:
@Secured(true)
@Only("admin", ["create", "delete", "update"])
@RESTController("/humans")
function HumansController -> DynamicObject()
That’s all for today. Next time we’ll see how compile an hybrid project with golo and java source code.
Tweet