Visualizzazione post con etichetta core. Mostra tutti i post
Visualizzazione post con etichetta core. Mostra tutti i post

Package e accesso

Ultime due lezioni, numero 10 sui package e 11 sui modificatori d'accesso, del corso Sun introduttivo a javaFX.

Niente da dire a commento aggiuntivo sui package, tutte cose che chi ha usato java conosce già. E quindi passiamo direttamente all'ultima lezione.

Accesso default

Se non specifichiamo nessun accesso intendiamo utilizzare l'accesso di default (come pare ragionevole), noto anche in javaFX come script-only, nel senso che tutto ciò che é definito in questo modo é visibile solo nel file corrente.

Questa modalità d'accesso é evidentemente specifica per javaFX, dato che in java non c'é questa interpretazione di un singolo file come unità a sé stante.

Accesso package

E' in javaFX quello che é per java l'accesso default, creando probabilmente qualche confusione. Anche perché per dichiarare che una variabile ha in javaFX un accesso package devo scrivere qualcosa del genere:

package var x;

Che può confondere le idee rispetto al concetto di package come unità contenente classi (e script).

In ogni caso: una variabile, classe o funzione dichiarata di accesso package é visibile dal codice presente nello stesso package.

Come esempio di uso della visibilità a livello package, creamoci un paio di file, nel primo, one.fx, scriviamo questo codice:

// tutorial/one.fx
package tutorial; // (1)

package var message = "Hello from one.fx!"; // (2)

// (3)
package function printMessage() {
println("{message} (in function printMessage)");
}

1: dichiariamo che il file é nel package tutorial.
2: definiamo una variabile con visibilità limitata al package corrente
3: definiamo una funzione con visibilità limitata al package corrente

Creiamo quindi un altro file, two.fx, che usa quanto definito in one.fx:

// tutorial/two.fx
package tutorial; // (1)

println(one.message); // (2)
one.printMessage(); // (3)

1: dichiariamo che il file é nel package tutorial.
2: usiamo la variabile message definita nell'oggetto one package corrente
3: definiamo la funzione printMessage() definita nell'oggetto one del package corrente

Questo modo di accedere variabili e fuzioni definite in one.fx ci spiega anche come funziona il trucco che permette a javaFX di farci definire codice e funzioni in un file all'esterno di classi: viene evidentemente definito un oggetto implicito che ha lo stesso nome del file.

Quindi per accedere la funzione printMessage() definita nel file one.fx scriviamo semplicemente:

one.printMessage();

Accesso protected

Qui siamo nel terreno conosciuto delle modalità di accesso java: l'accesso protected fa in modo che quanto definito sia accessibile all'interno del package corrente e da tutte le classi derivate da ogni classe del package stesso.

Riscriviamo l'esempio precedente dando, in one.fx, visibilità protected a un membro di classe pubblica:

package tutorial;

public class one {
protected var message = "Hello!";
}

La classe one sarà accedibile da ovunque, essendo pubblica, e message sarà accedibile da tutte le classi derivate da one, essendo protected. Per veder ciò, riscriviamo two.fx in questo modo:

import tutorial.one;

class two extends one {
function printMessage() {
println("Class two says {message}");
}
};

var t = two{};
t.printMessage();

Da notare, oltre a quanto detto per protected, un paio di cosettine: in javaFX la convenzione sui nomi é decisamente più rilassata (almeno in questo tutorial), e le classi hanno nomi che cominciano con lettere minuscole. Inoltre l'oggetto di tipo two viene costruito qui con la sintassi specifica di javaFX, ovvero, e non con quella java (var t = new two();).

Accesso public

Come per il public in java, massima accessibilità garantita per chi ha questo livello di accesso.

Accesso public-read

Altra interessante estensione di javaFX alle modalità di accesso proprie di java. Con public-read diciamo che una variabile é accedibile in lettura a tutti, ma può essere modificata solo nello script corrente.

E' possibile cambiare i privilegi in scrittura a questa variabile abbinando a public-read il modificatore di accesso package o protected.

Accesso public-init

Estende ulteriormente la public-read, rendendo la variabile anche inizializzabile da tutti. Ma, dopo l'inizializzazione, accedibile solo in lettura a livello public. L'accesso in scrittura, dopo la creazione, é gestito come nel caso public-read, ovvero solo nello script corrente per default.

Scrivere classi

Con la lezione numero 9 del corso Sun introduttivo a javaFX, torniamo a vedere cose che, per chi abbia un background java sono piuttosto scontate, si parla infatti, con un po' più di dettaglio di quanto si sia fatto precedentemente, di classi e oggetti in javaFX.

La differenza fondamentale tra java e javaFX, é che é stato rimossa la limitazione sul nome del file che dove corrispondere al nome della classe principale contenuta nel file stesso. E quindi si possono mettere tutte le classi che vogliamo in un unico file. Questo rende probabilmente la struttura di un progetto FX meno lineare di un java classico ma permette una più semplice scrittura di script.

Approfitteremo di questa feature di javaFX per scrivere tutto il codice di cui parliamo in questo post in un unico file fx.

Prima cosa, definiamo la classe Address in questo modo:

class Address {
var street: String;
var city: String;
var state: String;
var zip: String;
}

In pratica un indirizzo viene definito come un aggregato di quattro stringhe: via, città, stato, e cap.

Un poco più interessante la classe Customer, che definisce come suo dato membro un oggetto di tipo Address e tre funzioni che usano i dati della classe:

class Customer {
var firstName: String;
var lastName: String;
var phoneNum: String;
var address: Address;

function printName() {
println("Name: {firstName} {lastName}");
}

function printPhoneNum(){
println("Phone: {phoneNum}");
}

function printAddress(){
println("Street: {address.street}");
println("City: {address.city}");
println("State: {address.state}");
println("Zip: {address.zip}");
}
}

Per costruire un oggetto di tipo Customer, facciamo come si vede qui a seguire. In questo caso l'oggetto é costante (visto il def che lo introduce) ma sarebbe ovviamente potrebbe essere variabile:

def customer = Customer {
firstName: "John";
lastName: "Doe";
phoneNum: "(408) 555-1212"
address: Address {
street: "1 Main Street";
city: "Santa Clara";
state: "CA";
zip: "95050";
}
}

Definito customer di tipo Customer possiamo ora chiamare le funzioni definite per esso in questo modo:

customer.printName();
customer.printPhoneNum();
customer.printAddress();

Gerarchie di classi

E' possibile scrivere gerarchie di classi, dove classi figlie ereditano il comportamento di una classe madre. Se marchiamo una classe come astratta intendiamo che non siano creati oggetti di quel tipo. Vediamo qui un esempio:

abstract class Account {
var accountNum: Integer;
var balance: Number;

function getBalance(): Number {
return balance;
}

function deposit(amount: Number): Void {
balance += amount;
}

function withdraw(amount: Number): Void {
balance -= amount;
}
}

Data questa classe base possiamo definire ora una classe che la estende, aggiungendo dati e funzioni:

class SavingsAccount extends Account {
var minBalance = 100.00;
var penalty = 5.00;

function checkMinBalance() : Void {
if(balance < minBalance){
balance -= penalty;
}
}
}

Ed é possibile anche fare in modo che una classe figlia abbia un comportamento diverso dalle madre, possiamo infatti ridefinire una funzione nella classe figlia usando la parola chiave override:

class CheckingAccount extends Account {
var hasOverDraftProtection: Boolean;

override function withdraw(amount: Number) : Void {
if(balance-amount < 0 and hasOverDraftProtection){
// code to borrow money from an overdraft account would go here
}
else {
balance -= amount; // may result in negative account balance!
}
}
}

Data Binding e Trigger

La lezione numero 8 del corso Sun introduttivo a javaFX é invece piuttosto interessante, si parla qui di due funzionalità utili che sono implementate in modo elegante.

Per prima cosa parliamo di binding, ovvero della possibilità di correlare dati in modo che il cambiamento di uno si rifletta immediatamente nell'aggiornamento dell'altro.

E' ad esempio una funzionalità utilissima per codice progettato secondo i principi del MVC (Model View Controller), dove il Controller deve tenere in sincronia Model e View. La possibilità di stabilire esplicitamente un legame tra diverse variabili rende il codice molto più leggibile e manutenibile.

Vediamo ora esempi piuttosto banali di binding, giusto per prendere confidenza con l'implementazione javaFX del concetto.

Dichiariamo una variabile x e poi creiamo una costante y definita come connessa a x. Il fatto che sia costante ci impedisce di modificarla direttamente, il fatto che sia definita come "bind x" fa sì che sia in pratica un alias di x, ogni cambiamento di x si riflette in una cambiamento di y:

var x = 0;
def y = bind x;
x = 1;
println(y); // 1
x = 47;
println(y); // 47

E' possibile legare dati membro di una classe a variabili indipendenti:

var myStreet = "1 Main Street";
var myCity = "Santa Clara";
var myState = "CA";
var myZip = "95050";

def address = Address {
street: bind myStreet;
city: bind myCity;
state: bind myState;
zip: bind myZip;
};

println("address.street == {address.street}");
myStreet = "100 Maple Street";
println("address.street == {address.street}");

E' possibile creare un legame tra variabili usando una funzione, specificando la parola chiave bound:

var scale = 1.0;

bound function makePoint(xPos : Number, yPos : Number) : Point {
Point {
x: xPos * scale
y: yPos * scale
}
}

class Point {
var x : Number;
var y : Number;
}

var myX = 3.0;
var myY = 3.0;
def pt = bind makePoint(myX, myY);
println(pt.x); // 3

myX = 10.0;
println(pt.x); // 10

scale = 2.0;
println(pt.x); // 20

Nota che si crea un legame tra le variabili locali passate come parametri alla funzione e i dati membro dell'oggetto creato dalla funzione stesso. Una funzione bound é usata in pratica come un costruttore di oggetto che mantiene un legame con i parametri passati.
Nota inoltre che anche quando viene cambiato un valore globale utilizzato dalla funzione bound (nel nostro caso scale) i valori dell'oggetto creato dalla funzione bound vengono ricalcolati.

E' possibile anche usare bind in congiunzione con for per generare una nuova sequenza:

var seq1 = [1..10];
def seq2 = bind for (item in seq1) item*2;
printSeqs();

function printSeqs() {
println("First Sequence:");

for(i in seq1){
println(i);
}
println("Second Sequence:");
for(i in seq2){
println(i);
}
}

Come ci si può aspettare, la seq2 contiene dieci elementi, ognuno del quale é il doppio del corrispondente elemento della prima sequenza.

Trigger

Un trigger é, in pratica, una funzione che viene eseguita quando accade un certo evento su dei dati. In javaFX é possibile scrivere del codice che viene eseguito quando una certa variabile viene modificata usando il costrutto on replace, come esemplificato a seguire:

var password = "foo" on replace oldValue {
println("Old Value: {oldValue}");
println("New Value: {password}");
};

password = "bar";

Il trigger mantiene in oldValue, o come la voglio chiamare, il valore prima del replace, e quindi esegue il codice. Se facciamo correre il codice, vediamo che il trigger é eseguito due volte: quando la variabile su cui é posto viene inizializzata a "foo", e quando il suo valore viene cambiato in "bar".

Operatori ed espressioni

Coppia di lezioni piuttosto noiose, la sei e la sette, all'interno del tutorial sun introduttivo a javaFX.

Gli operatori sono in pratica gli stessi di java/c++, con qualche piccola variazione per far diventar matto il programmatore, vediamoceli rapidamente.

Per l'assegnamento si usa un'uguale (=)

result = num1 + num2;

Gli operatori aritmetici sono +, -, *, /, mod:

result = 10 mod 7; // 10 / 7 = 1 col resto di 3, dunque result sarà 3.

E' possibile combinare gli operatori aritmetici con l'assegnamento, con l'eccezione del modulo:

result += 1; // equivalente a result = result + 1;

Gli operatori unari sono -, --, ++, not (negazione booleana)

var success = false;
println(success); // false
println(not success); // true

Non ci sono sorpese negli operatori di uguaglianza e relazione: ==, !=, >, >=, <, <= Mentre gli operatori condizionali sono and, or Anche l'operatore per il confronto dei tipi é una vecchia conoscenza (per chi conosca java, si intende): instanceof

Espressioni

Un blocco é, a tutti gli effetti, equivalente a una funzione inline: circondato da parentesi graffe, "ritorna" il valore dell'ultima espressione inclusa. Se non c'é alcuna espressione inclusa, il blocco é di tipo Void

var nums = [5, 7, 3, 9];
var total = {
var sum = 0;
for (a in nums) {
sum += a
};
sum;
}

println("Total is {total}."); // 24

Il flusso condizionale di esecuzione é solitamente implementato usando la solita struttura if - else if - else:

if (age < ticketprice =" 0;"> 65) {
ticketPrice = 5;
}
else {
ticketPrice = 10;
}

Ma in javaFX é disponibile anche questa scorciatoia che appare molto concisa ed elegante:

ticketPrice = if (age <> 65) 5 else 10;

Le sequenze, che aevamo visto qui, sono, parlando tecnicamente, delle espressioni di ambito (in inglese: range) di cui é possibile specificare la distanza tra i vari elementi usando la parola chiave step:

var odds = [1..10 step 2];
var down = [10..1 step -1];

I loop su una sequenza sono implementati elegantemente con un for, iterando sugli elementi:

var days = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];

for (day in days) {
println(day);
}

Nota che la variabile day é generata al volo dal compilatore per esistere solo per la durata del ciclo for.

Il ciclo while ha invece una costruzione più tradizionale:

var count = 0;
while (count < count ="=">

Per modificare il flusso di esecuzione all'interno di un ciclo sono disponibili le espressioni continue e break:

for (i in [0..10]) {
if (i > 5) {
break;
}

if (i mod 2 == 0) {
continue;
}

println(i);
}

La gestione delle eccezioni avviene secondo lo schema stabilito dalle espressioni throw (per lanciarla) catch (per gestirla) finally (per specificare cosa fare in ogni caso, dopo aver gestito l'eccezione, o se non c'é stata eccezione)

...
if(somethingWeird) {
throw new Exception("Something weird just happened!");
}

...

try {
foo();
}
catch (e: Exception) {
println("{e.getMessage()} (but we caught it)");
}
finally {
println("We are now in the finally expression...");
}

Sequenze

Nella quinta lezione del tutorial sun su javaFX si parla di sequenze.
Una sequenza é una lista ordinata di oggetti. Un concetto simile all'enumerazione.

Al solito, se non si specifica il tipo della sequenza, ci pensa il compilatore ad inferirne uno. Ad esempio, queste due definizioni di sequenze costanti sono equivalenti:

def weekDays = ["Mon","Tue","Wed","Thu","Fri"];
def weekDays2: String[] = ["Mon","Tue","Wed","Thu","Fri"];

Si può usare una sequenza precedentemente definita per crearne un'altra. Queste due sequenze, definite come variabili sono perciò equivalenti - se weekDays é la sequenza definita qui sopra:

var days = [weekDays, ["Sat","Sun"]];
var days2 = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];

Per creare sequenze che formino una serie aritmetica si può usare questa notazione semplificata:

def nums = [1..100];

Si può usare una espressione booleana (ovvero un predicato) per creare una nuova sequenza a partire da una esistente:

def evenNums = nums[n | (n mod 2) == 0];

La sequenza evenNums contiene tutti i valori che erano in nums tali che il resto della loro divisione per due sia uguale a zero, ovvero i numeri pari.

L'accesso agli oggetti contenuti in una sequenza può essere effettuato sulla base dell'indice dell'elemento, a partire dall'indice 0, come da convenzione ereditata dal linguaggio C:

println(days[0]); // "Mon"

L'operatore sizeof ci permette di vedere quanti elementi siano in una sequenza:

println(sizeof evenNums); // 50

Una sequenza può essere definita come variabile (var) o costante (def). Nel primo caso, quindi, può essere modificata. Si noti che, tecnicamente parlando, le sequenze sono immutabili, quello che succede quando variamo una sequenza é che la vecchia viene distrutta e una nuova, variata secondo la nostra richiesta, ci viene ritornata.

Per inserire un nuovo elemento in coda a una sequenza usiamo il costrutto insert into:

var days = ["Mon"];
insert "Tue" into days;
insert "Fri" into days;
insert "Sat" into days;
insert "Sun" into days;

Possiamo inserire un nuovo elemento prima o dopo di un determinato indice con i costrutti insert before / insert after:

insert "Thu" before days[2];
insert "Wed" after days[1];

Per eliminare un elemento da una sequenza possiamo usare l'operatore delete in uno di questi due modi:

delete "Sun" from days;
delete days[0]; // "Mon"

Con delete posso anche rimuovere tutti gli elementi della sequenza in un colpo solo:

delete days;

Con l'operatore reverse posso creare una sequenza dove il primo elemento diventa l'ultimo e viceversa:

def count = [1..5];
var countdown = reverse count; // [5, 4, 3, 2, 1]

Per confrontare due sequenze si può usare l'operatore == che ritorna true solo nel caso le due sequenze abbiano lo stesso numero di elementi, e tutte le coppie di elementi nella stessa posizione siano uguali.

Nell'esempio a seguire le due sequenze sono considerate diverse:

def seq1 = [1,2,3,4,5];
def seq2 = [1,3,2,4,5];
println(seq1 == seq2);

Fare una sequenza a fette:

Con il costrutto seq[a..b] generiamo una partizione di sequenza che include i limiti passati:

def weekend = days[5..6];

Per definire un insieme aperto a destra usiamo seq[a..<>
def weekdays = days[0..<5];>
Possiamo non specificare il limite superiore, la sequenza conterrà tutti gli elementi a partire dal primo specificato con seq[a..]:

def weekend2 = days[5..];

Possiamo anche specificare che vogliamo includere tutti gli elementi a destra dell'elemento specificato tranne l'ultimo della sequenza originaria:

def days2 = days[0..<];

Oggetti e tipi di dato

La terza lezione del tutorial sun su javaFX é dedicata ai concetti di classe e oggetto.

Ecco un esempio di classe fx:

public class Address {
public var street: String;
public var city: String;
public var state: String;
public var zip: String;
}

Il punto e virgola a fine riga é opzionale, ma per chi abbia java nel suo background viene più naturale mettercelo.

Per definire un oggetto di tipo Address farò così:

def myAddress = Address {
street: "1 Main Street";
city: "Santa Clara";
state: "CA";
zip: "95050";
}

Ma lasciamo un attimo in sospeso classi e oggetti e passiamo a vedere i tipi di dato, ovvero la quarta lezione.

String

Una stringa può essere delimitata indifferentemente da singoli o doppi apici, e all'interno di una stringa é possibile quotare espressioni mettendole tra parentesi graffe:

var hi = 'Hello';
def name = "Joe";
var s1 = "{hi} {name}"; // s1 = 'Hello Joe'

A sua volta un espressione contenuta in una stringa può contenere stringhe, e così via:

def answer = true;
var s2 = "The answer is {if (answer) "Yes" else "No"}"; // s = 'The answer is Yes'

Un semplice modo per unire due stringhe é questo:

def one = "This example ";
def two = "joins two strings.";
def three = "{one}{two}";
println(three); // 'This example joins two strings.'

Number e Integer

Ci pensa il compilatore a scegliere il tipo appropriato delle nostre variabili e costanti, e questo vale anche nella scelta tra interi e reali, in ogni caso possiamo esplicitare la scelta dichiarando il tipo di variabile (nell'esempio a seguire, le righe commentate avrebbero lo stesso effetto delle righe precedenti):

def numOne = 1.0; // Number
// def numOne : Number = 1.0;
def numTwo = 1; // Integer
// def numTwo : Integer = 1;

Nota che con javaFX sono diventati disponibili tutti i tipi numerici di java (Byte, Short, Number, Integer, Long, Float, Double, Character), anche se si consiglia di non abusare della nuova libertà.

Boolean

Il tipo Boolean rappresenta due valori: true e false.

var isAsleep = true;

Duration

Usato per specificare una durata in unità temporali. Se ne parlerà meglio più avanti.

5ms; // 5 millisecondi
10s; // 10 secondi
30m; // 30 minuti
1h; // 1 ora

Void

Usato per indicare che una funzione é in realtà una procedura, e quindi non ritorna nulla. Dato che una funzione per default non ritorna nulla, si può fare a meno di indicare che sia di tipo Void (e nota che il tipo é Void con la V maiuscola)

function printMe() : Void {
println("I don't return anything!");
}

null

Invece null si scrive con la n minuscola. Indica la mancanza di un valore normale per una determinata variabile.

Scrivere script

Seconda lezione dal tutorial Sun su JavaFX, partiamo dicendo qualcosa di più sulle funzioni in questo linguaggio.

Per default, una funzione fx é una procedura, ovvero non ritorna nulla. Dunque le due funzioni che scrivo qui a seguire, hello() e hello2() sono esattamente uguali. Nota che il tipo del parametro tornato dalla funzione viene specificato dopo il nome e la lista dei parametri in input della funzione stessa. E che Void é indicato con la V maiuscola.

function hello() {
println("Hello");
}

function hello2() : Void {
println("Hello");
}

Per mostrare come si passano parametri in input ad una funzione, riscriviamo l'esempio visto nella lezione precedente nel modo a seguire - qui faccio anche la piccola variazione di non usare una variabile globale result in appoggio per la gestione locale delle singole funzioni, ma dichiaro result locale alle funzioni stesse.
Si noti che anche il tipo delle variabili in input alla funzione viene indicato dopo il nome del parametro.

add(100,10);
subtract(50,5);
multiply(25,4);
divide(500,2);

function add(argOne: Integer, argTwo: Integer) {
var result = argOne + argTwo;
println("{argOne} + {argTwo} = {result}");
}

function subtract(argOne: Integer, argTwo: Integer) {
var result = argOne - argTwo;
println("{argOne} - {argTwo} = {result}");
}

function multiply(argOne: Integer, argTwo: Integer) {
var result = argOne * argTwo;
println("{argOne} * {argTwo} = {result}");
}

function divide(argOne: Integer, argTwo: Integer) {
var result = argOne / argTwo;
println("{argOne} / {argTwo} = {result}");
}

function hello() {
println("Hello");
}

function hello2() : Void {
println("Hello");
}

Vediamo come agisce una funzione che accetta due parametri in input di tipo Integer e ritorna un altro Integer. Mi scrivo una nuova funzione addizionatrice che chiamo add2() e la chiamo come da tutorial:

var total = add2(1,300) + add2(23,52);
println("total is {total}");

function add2(argOne: Integer, argTwo: Integer) : Integer {
var result = argOne + argTwo;
println("{argOne} + {argTwo} = {result}");
return result;
}

Il risultato di questo pezzo di codice non dovrebbe essere sorprendente:

1 + 300 = 301
23 + 52 = 75
total is 376

E' lecito chiedersi come funziona la comunicazione dalla shell del sistema al nostro script fx. Dato che non c'é una funzione main, come fare a passargli parametri?

La risposta sta nella funzione run(), che é a tutti gli effetti una procedura, e accetta come parametro in input un array di stringhe.

La usiamo a seguire modificando leggermente il codice sopra visto, per permettere all'utente di effettuare operazioni con i valori che vuole lui.
Faccio un rapido test dell'input, per accertarmi di non avere eccezioni dalla parseInt() e poi chiamo le funzioni di calcolo parametrizzate con i valori passatimi dall'utente.

function run(args : String[]) {
if(args.size() < 2) {
println("Missing input parameter.");
}
else {
// Convert Strings to Integers
def numOne = java.lang.Integer.parseInt(args[0]);
def numTwo = java.lang.Integer.parseInt(args[1]);

// Invoke Functions
add(numOne,numTwo);
subtract(numOne,numTwo);
multiply(numOne,numTwo);
divide(numOne,numTwo);
}
}

Chiamando da shell la mia applicazione:

javafx fxTut.calc2 100 50

ho effettivamente i risultati attesi.

Primo approccio

Volendo lavorare con javaFX, sono andato sul sito omonimo, mi sono scaricato quanto c'é da scaricare, e sono passato al tutorial get started disponibile sul sito della sun.

Al lavoro, dunque.

Mi sono creato un progetto JavaFX su NetBeans, e un file al suo interno, con la piccola variazione, rispetto a quanto detto nel tutorial, di mettere il file non del default package (orrore!) ma in un apposito package che ho chiamato fxTut.

Il codice sorgente del mio primo file fx é pari pari quanto indicato dal tutorial, pur non avendo mai visto prima nulla scritto in questo linguaggio, le precedenti esperienze in java e perl, tanto per fare un paio di nomi, rendono il codice comprensibile.

Noto che dai linguaggi di scripting fx ha ereditato la mancanza di un main. Il codice viene semplicemente eseguito dalla prima riga in giù.

Molte le somiglianze con java, a partire dalla prima riga, la dichiarazione del package contenente il file (beh, questa é anche l'unica differenza tra il mio codice e quello standard del tutorial).

def evidentemente introduce una costante, var una variabile. Noto che anche qui ci si discosta da java e ci si richiama ai liguaggi di scripting, dato che non c'é tipizzazione esplicita degli oggetti.

Noto infine la println(), un ibrido tra la println java e le funzionalità di stampa dei linguaggi di scripting, con le parentesi graffe a fare da escape per i nomi delle variabili i cui valori vogliamo stampare.

package fxTut;

def numOne = 100;
def numTwo = 2;
var result;

add();
subtract();
multiply();
divide();

function add() {
result = numOne + numTwo;
println("{numOne} + {numTwo} = {result}");
}

function subtract() {
result = numOne - numTwo;
println("{numOne} - {numTwo} = {result}");
}

function multiply() {
result = numOne * numTwo;
println("{numOne} * {numTwo} = {result}");
}

function divide() {
result = numOne / numTwo;
println("{numOne} / {numTwo} = {result}");
}

Fatto correre con un F6 il programma all'interno di Netbeans ottengo il risultato atteso.

Come da tutorial, mi guardo l'esecuzione del mio programma anche da shell. Vado perciò nella directory build del mio progetto ed eseguo:

javafx fxTut.Calc

Dove javafx é la JVM estesa di FX, eseguibile che mi trovo nel bin di javafx-sdk, fxTut é il nome del package dove ho messo il mio codice, Calc é il nome della mio file fx (il sorgente era Calc.fx, qui troviamo il bytecode java Calc.class, l'estensione class non viene esplicitata quando si passa il file alla macchina virtuale, come da solite convenzioni java).

Fatto tutto a modo, il risultato é quello atteso, anche se non esattamente esaltante.