Golo <3 Java

Golo c’est un langage qui “tourne” dans la JVM, il est donc tout naturel qu’il puisse “communiquer” avec elle. C’est Ă  dire ? : Golo peut utiliser toute les fonctionnalitĂ©s embarquĂ©es de java (les packages de base), mais aussi des librairies externes (des jars d’autres frameworks, ou les votres), on parle bien sĂ»r ici, d’INTEROPERABILITE.

Golo et Java, utiliser les fonctionnalités de base

Exemple : Les Strings & co

Alors de fait vous les utilisez dans Golo : var hello = "hello world !" mais aussi avec les objets dans Golo qui “portent” les primitives de base :

var age = 42
var geekAge = age: toString() + " ans"

Cet exemple est crétin on peut trÚs bien caster directement :

var age = 42
var geekAge = age + " ans"

Mais vous pouvez aussi utiliser les mĂ©thodes statiques de l’objet String :

import java.lang.String

function main = |args| {

	println(String.format("Hello i am %s", "@K33G_ORG"))

}

Retenez bien :

  • on utilise le . pour accĂ©der aux membres statiques et : pour les membres d’instances. Ca surprend au dĂ©but, mais en fait on y gagne en lisibilitĂ©
  • n’oubliez pas le import java.lang.String sinon ça ne marchera pas

Autre exemple : les HashMaps

Je voue une passion inconsidérée et inexpliquées aux HashMaps, donc un petit exemple avant de rentrer dans le dur

import java.lang.String
import java.util.HashMap

function main = |args| {

	var heroes = HashMap() #  = new HashMap()

	heroes: put("CB", "Claire Bennet")
	heroes: put("HN", "Hiro Nakamura")
	heroes: put("PP", "Peter Petrelli")

	foreach(heroe in heroes: entrySet()) {
		println(
			String.format("key : %s -> name : %s", 
				heroe: getKey(), 
				heroe: getValue()
			)
		)	
	}
}

vous obtiendrez donc :

key : PP -> name : Peter Petrelli
key : HN -> name : Hiro Nakamura
key : CB -> name : Claire Bennet

Donc, vous voyez, on dispose de la puissance de Java au service de Golo! :) Mais passons Ă  plus fun.

Golo & les librairies externes

Faites votre jar : jouons au pays ACME avec Buster

Nous allons faire notre propre librairie, comme cela vous pourrez la modifier à loisir pour vos expérimentations. Nous avons cÎté Java :

# Une interface Toon.java

package acme.looniversity;

public interface Toon {
    String name();
    void name(String value);
    String description();
    void description(String value);

    void talk(String message);
    void run();
    void scream();
}

# Une classe TinyToon.java (qui implémente Toon)

package acme.looniversity;

public class TinyToon implements Toon{
    private String name="John Doe";
    private String description="Somebody";

    private int age=0;

    public int age() { return age; }

    public void age(int age) { this.age = age; }

    public String name() { return this.name; }

    public void name(String value) { this.name = value; }

    public String description() { return this.description; }

    public void description(String value) { this.description = value; }

    public void talk(String message) {
        System.out.println(this.name + " is talking : "+ message);
    }
    public void run() {
        System.out.println(this.name + " is running");
    }
    public void scream() {
        System.out.println(this.name + " is screaming");
    }
}

# Un singleton BusterBunny.java

package acme.looniversity;

public class BusterBunny extends TinyToon {

    private static BusterBunny theOnlyOne;

    private BusterBunny() {
        this.name("Buster Bunny");
        this.description("a blue male rabbit");
    }

    public static BusterBunny getInstance() {
        if(BusterBunny.theOnlyOne == null) {
            BusterBunny.theOnlyOne = new BusterBunny();
        }
        return BusterBunny.theOnlyOne;
    }
}

Jouons avec Buster

Vous me faites un jar tinytools.jar avec les codes java ci-dessus, puis vs crĂ©ez un nouveau script golo acme.golo (au mĂȘme endroit que le jar pour le moment) :

# acme.golo

module acme

import acme.looniversity.BusterBunny

function main = |args| {

	var buster = BusterBunny.getInstance() # call static method

	buster: run()
	buster: scream()
	buster: talk("Hello")

	println("buster name : " + buster: name())
	println("buster description : " + buster: description())

	buster: age(13)

	var busterAgain = BusterBunny.getInstance()

	println("Age : " + busterAgain: age()) # it's a singleton

}

Pour exécuter ce script en précisant le fichier tinytools.jar utilisé , créez un script acme.sh (et rendez-le exécutable chmod +x) :

# !/bin/sh

export CLASSPATH_PREFIX=${CLASSPATH_PREFIX}:tinytools.jar

gologolo $1 

Maintenant, lancez ./acme.sh acme.golo et vous allez obtenir :

Buster Bunny is running
Buster Bunny is screaming
Buster Bunny is talking : Hello
buster name : Buster Bunny
buster description : a blue male rabbit
Age : 13

# Explications

  • var buster = BusterBunny.getInstance() on appelle la mĂ©thode statique getInstance() pour avoir une instance (et la seule) de Buster
  • buster: age(13) : on change l’age de Buster en utilisant une mĂ©thode d’instance
  • var busterAgain = BusterBunny.getInstance() on essaye d’avoir une 2Ăšme instance de Buster
  • et en fait c’est bien la mĂȘme (un singleton donc) puisque l’on s’aperçoit que l’age de busterAgain est dĂ©jĂ  Ă©gal Ă  13

Buster veut une copine, l’hĂ©ritage cĂ©mal, la composition c’est bon

En Golo, hĂ©riter d’une classe Java n’est pas possible (pour le moment), mais nous allons voir que ce n’est pas forcĂ©ment utile. Je pourrais faire une classe java BabsBunny, mais je n’ai pas envie de refaire ma librairie java, donc je vais jouer avec les DynamicObjects (encore, mais j’aime tellement ça) et la composition et une sorte de pattern proxy. Modifiez donc le code de acme.golo :

module acme

import acme.looniversity.TinyToon

function BabsBunny = -> DynamicObject():
	acmeInstance(TinyToon()):
	define("init", |this| {
		this: acmeInstance(): name("Babs Bunny")
		this: acmeInstance(): description("a pink female rabbit")
		this: acmeInstance(): age(12)
		return this
	}):
	define("age", |this| -> this: acmeInstance(): age()):
	define("name", |this| -> this: acmeInstance(): name()):
	define("description", |this| -> this: acmeInstance(): description()):
	define("run", |this| -> this: acmeInstance(): run()):
	define("scream", |this| -> this: acmeInstance(): scream()):
	define("talk", |this, message| -> this: acmeInstance(): talk(message))



function main = |args| {

	var babs = BabsBunny(): init()

	babs: run()
	babs: scream()
	babs: talk("Hello")

	println("babs name : " + babs: name())
	println("babs description : " + babs: description())	

	println("Age of babs : " + babs: age())

}

J’ai donc ajoutĂ© un DynamicObject BabsBunny qui a une propriĂ©tĂ© acmeInstance “contenant” une instance de la classe java TinyToon et ensuite je reproduis les comportements de cette classe en crĂ©ant des mĂ©thodes qui appellent les mĂ©thodes de la classe java.

Vous pouvez lancer ./acme.sh acme.golo et vous allez obtenir :

Babs Bunny is running
Babs Bunny is screaming
Babs Bunny is talking : Hello
babs name : Babs Bunny
babs description : a pink female rabbit
Age of babs : 12

# La mĂȘme chose mais avec des mixins car il y a beaucoup de Tinytoons au pays ACME

Parce que le pays ACME n’est pas uniquement habitĂ© par Babs et Buster, que le copier/coller cĂ©mal, je vais faire un peu de refactoring de code :

Je vais créer un DynamicObject _TinyToon_ dont tous mes golo tinytoons hériteront via mixin() :

module acme

import acme.looniversity.TinyToon
import java.lang.String

# an other way to get a Babs Bunny

function _TinyToon_ = -> DynamicObject():
	acmeInstance(TinyToon()):
	define("super", |this, name, description, age| {
		this: acmeInstance(): name(name)
		this: acmeInstance(): description(description)
		this: acmeInstance(): age(age)
		return this
	}):
	define("age", |this| -> this: acmeInstance(): age()):
	define("name", |this| -> this: acmeInstance(): name()):
	define("description", |this| -> this: acmeInstance(): description()):
	define("run", |this| -> this: acmeInstance(): run()):
	define("scream", |this| -> this: acmeInstance(): scream()):
	define("talk", |this, message| -> this: acmeInstance(): talk(message))


function BabsBunny = -> DynamicObject():
	mixin(_TinyToon_()):
	define("init", |this| {
		this: super("Babs Bunny", "a pink female rabbit", 12)
		return this
	})

function ElmyraDuff =  -> DynamicObject():
	mixin(_TinyToon_()):
	define("init", |this| {
		this: super("Elmira Duff", "a kid, redheaded, female human", 14)
		return this
	}):
	define("chases", |this, toon| {
		println(String.format("Help ! I'm %s : %s, i'm chased by Elmira :(",toon: name(),toon: description()))
	})

function main = |args| {

	var babs = BabsBunny(): init()

	var elmira = ElmyraDuff(): init()

	elmira: chases(babs)

}

Encore une fois lancez ./acme.sh acme.golo et vous allez obtenir :

Help ! I'm Babs Bunny : a pink female rabbit, i'm chased by Elmira :(

Java aussi peut utiliser Golo, mais 


LĂ  aussi, c’est possible, mais je ne vais pas m’étendre sur le sujet cette fois-ci, car ça peut faire un prochain article complet (ie: une application java scriptable en Golo), en attendant vous pouvez aller lire la documentation sur le sujet http://golo-lang.org/documentation/next/# _golo_class_loader.

Conclusion

“Si vous ne savez pas le faire en Golo, vous pourrez le faire en Java 
 Mais en Golo vous pouvez en faire un maximum.”

42.

blog comments powered by Disqus

Related posts