Ormai si sta parlando in diversi lidi del rilascio dei sorgenti di una prima versione “parecchio alfa” (non per niente definita pre-alfa 1) di IronRuby tuttavia non c’è niente di meglio che esplorare e sperimentare in prima persona sia le potenzialità che il codice sorgente stesso di questa nuova implementazione di Ruby totalmente basata su .NET Framework. Trattandosi di una versione ampiamente preliminare è ovvio che non tutto funzioni come dovrebbe così come è ovvio che manchino molti pezzi, però personalmente trovo che il progetto sia già in uno stato relativamente più che ottimo: la maggior parte delle mancanze risiedono più in metodi non ancora implementati per i tipi base che altro, ma John Lam ha chiarito come lui e il suo team abbiano preferito concentrarsi maggiormente su AST e parser ma soprattutto sulla struttura del core language, dispatcher per gestire da subito i blocchi tipici di Ruby e interoperabilità con .NET. Credetemi però, avere già tutto questo funzionante dopo pochi mesi e con buone prestazioni nonostante la scarsa ottimizzazione messa in atto è un risultato non indifferente, soprattutto nel contesto di un linguaggio che purtroppo manca ancora oggi di specifiche scolpite sulla pietra e dove l’unico set di specifiche è rappresentato dall’MRI ufficiale, di cui però il team di IronRuby non può consultare i sorgenti per motivi prettamente legali. Per un’altra iniezione di ottimismo basta poi dare un’occhiata al sorgente stesso di IronRuby potendone già constatare pulizia e chiarezza, tanto che nel giro di pochi minuti è possibile avere un’idea di massima su come e dove andare a mettere le mani per cominciare ad estendere in prima persona l’implementazione. Per quanto mi riguarda ho l’impressione che IronRuby si evolverà in un progetto molto importante e mi sembra che ci sia anche un crescente entusiasmo da parte dei rubysti che al tempo stesso sono o sono stati sviluppatori .NET, cosa che mi fa ben sperare per una buona partecipazione al progetto da parte della comunità.
Ora però cominciamo a fare qualche esperimento, compilando prima di tutto i sorgenti di IronRuby. Fortunatamente non è necessario avere installato Visual Studio o altri ambienti di sviluppo, basta avere una normale installazione di .NET 2.0 (anche soltanto redist, non serve l’SDK) e un editor di testo/codice decente. All’interno dell’archivio compresso troverete il file Build.cmd che contiene già le impostazioni per msbuild.exe, molto probabilmente però dovrete specificarne all’interno il path completo sostituendo le variabili. Nel mio caso, Build.cmd è diventato:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\msbuild.exe
/p:Configuration=Release /t:Rebuild IronRuby.sln
Per la cronaca IronRuby può essere compilato anche con Mono in Windows o Linux, anche se allo stato attuale è necessario sfruttare una build realizzata dai sorgenti nel repository SVN. La compilazione genererà tra le varie DLL anche l’eseguibile rbx.exe che è una sorta di incrocio tra ruby.exe (interprete) e IRB (console interattiva): eseguendolo senza alcun parametro RBX parte in modalità interattiva, in pieno stile IRB, altrimenti specificando un file/script in Ruby come parametro quest’ultimo verrà eseguito direttamente proprio come con l’interprete tradizionale. Per le nostre prime prove giocheremo un po’ con la classe String. Anzi, per ora sarebbe meglio dire MutableString visto il seguente output da RBX:
>>> "CIAO".class
=> MutableString
L’output in IRB invece è:
irb(main):001:0> "CIAO".class
=> String
Come già esplicitamente detto da John Lam, questo comportamento verrà sistemato con i prossimi rilasci, tuttavia l’occasione ci permette di mettere in evidenza come una stringa in Ruby sia effettivamente mutabile dal momento che il suo contenuto può essere modificato senza necessariamente generare una nuova istanza. Proseguendo con le prove, si può incontrare fin da subito una testimonianza dell’incompletezza dei metodi per i tipi base:
>>> "CIAO".reverse
System.MissingMethodException: undefined local variable or method `reverse' for
ciao:MutableString in Ruby.Builtins.Kernel.MethodMissing(CodeContext context, Object self,
Proc proc, SymbolId name, Object[] args) in j:\ir\pre-alpha1\Src\Ruby\Builtins\Kernel.cs:riga 169
[...]
La mancanza del metodo MutableString#reverse genera un’eccezione, tuttavia in Ruby potremmo intercettare la chiamata a un metodo non esistente sfruttando l’hook Object#method_missing che è chiamato automaticamente ogni volta che viene invocato un metodo non definito per un oggetto. Proviamo a sfruttare questo hook per vedere come si comporta IronRuby:
class MutableString
def method_missing(method_name, *args)
puts "Sorry, #{method_name} does not belong to me."
end
end
Basta copiare e incollare il codice in RBX (proprio come faremmo in IRB) e poi chiamare un metodo non definito per un oggetto di tipo MutableString, come per esempio lo stesso reverse:
>>> "CIAO".reverse
Sorry, reverse does not belong to me.
=> nil
Grande, Object#method_missing c’è e funziona! Però a noi il metodo MutableString#reverse serve proprio, riusciremo a sfruttare già in questa versione di IronRuby il concetto di classi aperte implementandolo direttamente via codice Ruby? Proviamo ampliando il codice di esempio di poco fa:
class MutableString
def method_missing(method_name, *args)
puts "Sorry, #{method_name} does not belong to me."
end
def reverse
reversed = " " * self.length
precalculated = self.length - 1
self.length.times do |i|
reversed[i] = self[precalculated - i]
end
reversed
end
end
Come prima, incolliamo il codice in RBX e poi proviamo a invocare il metodo che abbiamo appena definito:
>>> "CIAO".reverse
=> "OAIC"
>>> "CIAO".my_undefined_method
Sorry, my_undefined_method does not belong to me.
=> nil
Funziona tutto, veramente ottimo! Ora però la faccenda comincia a farsi un po’ più complicata perché vogliamo che il nostro metodo MutableString#reverse sia implementato “nativamente” in IronRuby, per motivi puramente prestazionali ma anche perché è giusto che sia così trattandosi di un metodo effettivamente appartenente alla classe String in Ruby. In pratica è giunto il momento di cominciare a giocare con i sorgenti in C# di IronRuby, anche se lo faremo in un messaggio successivo