Archivio per il mese di maggio 2008



IronRuby sempre più vicino a Ruby on Rails

Se non è in grado di far girare Ruby on Rails, allora non è Ruby… più o meno con queste parole John Lam, agli inizi dello sviluppo di IronRuby, aveva sottolineato la volontà di ottenere un’implementazione del linguaggio che fosse il più fedele possibile all’MRI (l’interprete originale di Matz). Oggi, con questo suo tweet, arriva la prima dimostrazione pratica di come questo obiettivo sia ormai sempre più vicino. Ovviamente manca ancora parecchio lavoro per completare IronRuby e attualmente il team è dedicato interamente a implementare e sistemare tutte le parti necessarie a poter effettuare l’hosting di una semplice applicazione RoR giusto in tempo per la RailsConf 2008 che avrà inizio tra pochi giorni, ma il ritmo sembra ormai molto buono. E’ interessante far notare che negli ultimi due mesi il lavoro del team di IronRuby si è fatto molto più trasparente in seguito a una forte critica sviluppatasi direttamente sulla mailing list, in cui si faceva notare come l’assenza di aggiornamenti sullo stato dei lavori e i commit in SVN abbastanza rari rendevano il lavoro di contribuzione e di testing molto difficile. La discussione ha generato un dialogo che ha portato a commit decisamente più frequenti, post dei diff sulla mailing list e review del codice e dei nuovi sviluppi… e la comunità che si sta formando intorno ad IronRuby ha apprezzato. Personalmente in queste ultime due settimane di silenzio sul blog ho avuto modo, tra le varie attività, di approfondire più seriamente gli internals di IronRuby provando a implementare qualche funzionalità mancante e devo ammettere che il suo codice e la struttura generale del progetto si sono dimostrati dannatamente ottimi e relativamente facili da capire nonostante non sia ancora esistente documentazione pubblica in merito (sarebbe stata inutile dal momento che il core ha cominciato a stabilizzarsi solo di recente). Se nel frattempo io mi sono divertito con metodi semplici come Kernel#rand e Kernel#srand per poi passare a Kernel#system con relativa classe Process::Status per cominciare a prendere familiarità con il progetto, qualcuno si è spinto ben oltre iniziando a ricreare un’implementazione di Shoes su IronRuby basandosi sulle API .NET di Windows Forms… potremmo chiamarlo IronShoes? Insomma ad oggi sono fortemente ottimista riguardo al futuro di IronRuby soprattutto visti gli ultimi sviluppi. Sono ottimista anche per la situazione di Ruby in generale perché stanno arrivando segnali molto interessanti dalla comunità, ma preferisco parlare di questo in un post successivo.

Mi mancava giusto Twitter

Non ho mai visto di buon occhio Twitter, sono sincero. Non ho mai capito per quale motivo dovrei sbandierare a chissà chi quello che sto facendo, costantemente, soprattutto nell’inutilità di frasi tipo "ehi sto uscendo di casa" oppure "sto andando a letto". Oh wow, chissenefrega. Probabilmente quelle poche volte che ho provato a curiosare mi sono sempre trovato di fronte a esempi sbagliati (soggettivamente parlando, sia chiaro), forse ho anche sofferto un po’ di sindrome da preconcetto, ma giungendo al sodo la mia impressione è sempre stata quella… tanto è vero che ho aperto un account su Twitter. Coerenza, questa sconosciuta!

No non sono impazzito, non solo perché un pazzo non può impazzire ma perché mi sono accorto di recente che su Twitter oltre a poter intercettare segnalazioni rilevanti con tempi quasi da record possono nascere anche brevi ma interessanti discussioni tra developer e appassionati di tecnologia, un fatto se vogliamo abbastanza paradossale se pensiamo all’essenzialità della comunicazione che caratterizza questo strumento. Rapidità, in questo periodo per me è un aspetto rilevante e al tempo stesso vedo il mio tumblelog su Tumblr come uno strumento differente da Twitter non solo nelle modalità ma anche nello scopo. Per ora la mia scelta ha una connotazione puramente sperimentale, devo ancora entrare nell’ottica e devo iniziare a inserire un po’ di gente da seguire però nel frattempo ho scoperto twhirl, un ottimo client Twitter basato su Adobe AIR (Windows e Mac OS X, per cui devo cercare ancora qualcosa per Linux) carino a vedersi e ricco di funzionalità che rende la fruizione del servizio ancora più comoda e veloce. Vedremo come andrà a finire, fatico sempre a metabolizzare certi servizi o strumenti non essendo mai stato particolarmente convinto o attratto dalla tendenza al sociale-a-tutti-i-costi degli ultimi anni, però con il tumblelog ha funzionato per cui chissà…

ILX: il CIL di .NET esteso per l’interoperabilità con i linguaggi funzionali

Facendo un po’ di ricerche sparse sono incappato nell’ennesimo progetto interessante targato Microsoft Research: ILX. Alla base di questo progetto, che porta la firma di Don Syme (già ideatore nonché sviluppatore principale di F#), vi è l’idea di ampliare il CIL destinato a essere elaborato dal CLR con lo scopo di ottenere un linguaggio intermedio che, rispetto a quello attuale, supporti particolari estensioni espressamente mirate a un miglior supporto e a una maggiore integrazione dei linguaggi funzionali sulla piattaforma .NET. Curiosamente non si tratta di un’idea nuova ma i paper risalgono addirittura al 2001 e sono stati presentati a un workshop di quel periodo. Le estensioni proposte permettono di ottenere un supporto diretto per:

  • polimorfismo parametrico, il quale è stato poi effettivamente implementato a livello nativo quando sono stati introdotti i generics nel CLR (Syme è effettivamente uno dei padri dell’implementazione dei generics in .NET).
  • unioni discriminate, ovvero i variant record (o il tipo variant) che sono nativi in linguaggi come ML e derivati o Haskell mentre in linguaggi come Nemerle e F# sono implementati sotto forma di zucchero sintattico con traduzione nel tipico modello a oggetti da parte dei relativi compilatori.
  • funzione come oggetto (first-class function, da non confondersi con i delegate di C# anche se il concetto è in parte simile), closure e thunk (che sarebbe anche un passo in avanti per call/cc).

Qualcuno potrà pensare che in tutto questo tripudio di estensioni manchi all’appello qualche forma di supporto per le chiamate tail utili per la cosidetta tail recursion, in realtà non vi è nessuna dimenticanza poiché il CLR le ha sempre supportate nativamente anteponendo nell’IL il prefisso tail. alle istruzioni call, callvirt e calli (quest’ultimo link è locale poiché l’originale è recuperabile solo dalla cache di Google, ma prima che sparisca…).

Con queste estensioni sarebbe possibile offrire una base comune agli implementatori di linguaggi sulla piattaforma .NET permettendo loro di spostare la gestione di costrutti tipici in certi linguaggi verso la macchina virtuale piuttosto che delegandone a ogni singolo compilatore la traduzione negli altri costrutti supportati attualmente, potendo offrire a questo punto anche delle ottimizzazioni a basso livello nella macchina virtuale stessa. Da un certo punto di vista è la stessa idea di base, anche se a un livello molto differente, che ha portato alla nascita del DLR sotto forma di libreria.

Per avere una visione completa di questo progetto vi riporto il link al paper completo in PDF presentato al BABEL’01 (si è dimostrata una lettura piuttosto interessante) e il link diretto alla reference di ILX (purtroppo solo in formato DOC). Per la cronaca, nella pagina dedicata al BABEL’01 è possibile trovare molti altri documenti interessanti.

Prove tecniche di programmazione in Nemerle [1ª parte]

Ormai è da qualche mese che ho deciso di elevare F# a mio linguaggio dell’anno e gli darò sicuramente spazio su questo blog nel prossimo futuro, tuttavia nell’ultimo periodo sono stato distratto da Nemerle, un linguaggio compilato a tipizzazione statica costruito anch’esso sulla piattaforma .NET e che unisce contemporaneamente caratteristiche tipiche dei linguaggi funzionali, imperativi e orientati agli oggetti. Nonostante a parole F# e Nemerle possano sembrare linguaggi equivalenti, nella realtà tra i due vi sono differenze sostanziali tanto che quest’ultimo ha:

  • un approccio maggiormente OO-centrico
  • un sistema di meta-programmazione particolarmente potente attraverso l’utilizzo di macro à la Lisp che lo rende particolarmente estendibile

In effetti la meta-programmazione è un elemento chiave di Nemerle tanto che il core stesso vi si basa pesantemente, vi basti pensare che costrutti base del linguaggio come if, for, foreach e while sono definiti in realtà attraverso delle macro:

macro @if (cond, e1, e2) syntax ("if", "(", cond, ")", e1, Optional (";"), "else", e2) { <[ match ($cond) { | true => $e1 | _ => $e2 } ]> }

Dal codice è possibile notare come la macro if sia implementata utilizzando internamente una caratteristica tipica di molti linguaggi funzionali definita pattern matching. Curiosamente l’applicazione del pattern matching in Nemerle può essere sfruttata direttamente in altri costrutti come foreach omettendo la keyword match:

1 def range = $[0 .. 5]; 2 3 foreach (num in range) { 4 | num when num % 2 == 0 => print($"$num: even | ") 5 | _ => print($"$num: odd | ") 6 } 7 8 // OUTPUT: 9 // 0: even | 1: odd | 2: even | 3: odd | 4: even | 5: odd |

 

  • riga 1: in questa riga istanziamo un range, ma è da notare che esistono anche le list comprehension tipiche di Python (anche se con una sintassi un po’ più criptica).
  • riga 4: il primo pattern prevede che il numero sia pari, se il valore non combacia con il pattern allora si passa a quello successivo.
  • riga 5: l’utilizzo di _ nel pattern matching equivale a un catch all (una sorta di clausola default in uno statement switch) in cui vi si entra se non si verifica alcun match con i pattern specificati in precedenza.

Dall’esempio si può notare inoltre come non sia stato specificato alcuni tipo per gli oggetti, questo grazie al sistema di type inference che permette al compilatore di dedurre i tipi in fase di compilazione. Anche il costrutto try … catch … finally è stato leggermente rivisto rispetto al solito per uniformarsi alla filosofia del linguaggio:

def (a, b) = (12, 0); try { def n = a / b; } catch { | e is DivideByZeroException => print($"You got to have some guts to divide $a by $b!"); | e is Exception => { // ... } } // OUTPUT: // You got to have some guts to divide 12 by 0!

E’ evidente quindi come il pattern matching possa essere sfruttato in svariati ambiti che non si limitano a semplici stringhe o numeri, infatti può essere applicato anche nel controllo di tipi (attraverso is, come nell’esempio di try … catch), su enum o variants (un altro tipo che arriva direttamente dal mondo funzionale), su tuple e liste, su proprietà o campi di un’istanza di classe. Un’altra applicazione particolare del pattern matching si può trovare nelle espressioni regolari:

foreach (str in ["ciao", "aiuola", "casa", "44 gatti"]) { regexp match (str) { | "^a.*a$" => printf("\"%s\" inizia e termina con la lettera \"a\"\n", str); | @"^(?<num : int>\d+).+" => printf("\"%s\" inizia con il numero %d\n", str, num); | _ => printf("Nessun match per \"%s\"\n", str); } } /* OUTPUT: Nessun match per "ciao" "aiuola" inizia e termina con la lettera "a" Nessun match per "casa" "44 gatti" inizia con il numero 44 */

Come accennato in precedenza esiste un tipo Variant (simile al tipo datatype di ML, a cui Nemerle in parte si ispira) il quale, almeno a prima vista, potrebbe sembrare ridondante con il tipo Enum derivato da C# in quanto apparentemente simili ma che in realtà risulta essere molto più potente e flessibile. Un esempio, preso dal sito di Nemerle ma leggermente espanso, vale più di mille parole:

1 variant RgbColor { 2 | Red 3 | Yellow 4 | Green 5 | Different { 6 red : float; 7 green : float; 8 blue : float; 9 } 10 } 11 12 def colors = [ RgbColor.Red, 13 RgbColor.Green, 14 RgbColor.Different(0, 127, 255), 15 RgbColor.Different(blue = 255, red = 0, green = 127) ]; 16 17 18 def string_of_color(color : RgbColor) : string { 19 | RgbColor.Red => "red" 20 | RgbColor.Yellow => "yellow" 21 | RgbColor.Green => "green" 22 | RgbColor.Different(r, g, b) => $"rgb($r, $g, $b)" 23 } 24 25 foreach (color in colors) printf("%s\n", string_of_color(color)); 26 27 /* OUTPUT: 28 red 29 green 30 rgb(0, 127, 255) 31 rgb(0, 127, 255) 32 */

Possiamo notare alcuni particolari:

  • riga 5: il tipo variant permette di creare nuove opzioni partendo da informazioni aggiuntive, in questo caso un colore non contemplato dalle opzioni del tipo variant RgbColor può essere ugualmente espresso sotto forma di valori RGB
  • riga 14-15: il costruttore per l’opzione RgbColor.Different può essere invocato passando ad esso i valori degli argomenti con lo stesso ordine della definizione dell’opzione stessa oppure sfruttando i named parameter supportati da Nemerle
  • riga 18-19: come nel caso precedente di foreach, possiamo omettere match anche nello sviluppo di funzioni se esso si trova all’inizio del corpo della funzione
  • riga 22: possiamo effettuare il binding di variabili ai campi di un’opzione di un tipo variant nello stesso modo in cui abbiamo invocato il costruttore dell’opzione stessa, ovvero seguendo l’ordine della definizione dei campi (come nell’esempio) oppure sfruttando i named parameters, con cui avremmo potuto scrivere:

    | RgbColor.Different(red = r, blue = b, green = g) => $"rgb($r, $g, $b)"

Questi sono solo alcuni esempi di programmazione in Nemerle per cominciare a comprendere la filosofia del linguaggio, ne seguiranno ulteriori in altri messaggi ma prima ci tengo a esprimere alcune considerazioni. Nemerle rimane un progetto portato avanti da un gruppo di sviluppatori dell’università di Wrocław senza fondi o supporto esterni, al contrario di F# che è nato in seno al progetto Microsoft Research ed diventato recentemente parte integrante della piattaforma .NET. Questo significa che, nonostante la solidità del design del linguaggio e la sua implementazione generalmente stabile, non è esente da problemi o da qualche mancanza sparsa (personalmente una delle maggiori, anche se by-design, risiede nel fatto che non è possibile implementare iteratori in funzioni locali usando yield). Inoltre all’apparenza il progetto può sembrare poco supportato dai suoi sviluppatori e al limite dell’abbandono, ma in realtà viene portato avanti e attualmente uno degli obiettivi è il rilascio ogni 1~3 mesi di nuove CTP dell’attuale versione instabile 0.9.4. Alla fine dei conti si tratta comunque di un linguaggio abbastanza interessante per certe sue caratteristiche quindi vale la pena giocarci un po’. Tra l’altro è possibile usare Nemerle anche in Linux dal momento che si integra molto bene con Mono, non per niente tutte le mie prove sono state eseguite su una Xubuntu 8.10 con Nemerle 0.9.3 e Mono 1.2.6 (come da repository ufficiali di Hardy Heron) usando SciTE come editor, anche se si tratta di un linguaggio supportato da MonoDevelop.