Tool Command Language: il papa’ di Java

E’ notizia fresca di stampa il rilascio di Tcl 8.6, che introduce parecchie novità a dispetto del fatto che sia una “minor” release.

 

In particolatre Tcl 8.6 introduce un motore “stackless”, integra nel linguaggio le estensioni OOP, ed aggiunge le coroutine.

Parliamo quindi diffusamente di Tcl, un linuaggio che ho sempre trascurato perché mi sembrava macchinoso e un po’ brutto/fatto  male…ma mi sono dovuto ricredere.

Ho avuto modo di leggere questo articolo su Tcl, scritto dal creatore diRedis, Antirez:

http://antirez.com/articoli/tclmisunderstood.html
L’articolo è del 2006, ma mi ha fatto riflettere sulla storia di Tcl e su alcuni fatti che si stanno verificando oggi: vedremo perché.

Iniziamo con ordine: Tcl nasce nel 1988, ed è stato creato da John Kenneth Ousterhout.
Tcl è stato per lungo tempo un linguaggio di scripting molto potente, con un’ampia capacità di estensione.
Deve il suo successo anche ad un’ottima libreria grafica (Tk).
Fu patrocinato dalla Sun, ed in un certo senso è il papà di Java.

Tcl è basato su una serie di semplice idee:

  1. Ogni istruzione di tcl è un comando
  2. Come per le shell unix, c’è una sintassi per sostituire il risultato di un comando usando le parentesi quadre…
  3. Esiste un solo tipo, la stringa.
  4. E’ possibile raggruppare comandi tra parentesi graffe { } per evitare che vengano interpretati immediatamente
  5. E’ possibile creare nuovi comandi in modo che siano indistinguibili da quelli nativi
  6. Esiste un meccanismo per valutare del codice nel contesto del comando chiamante (uplevel). Questo meccanismo è simile alle funzioni lambda tipiche dei linguaggi funzionali come lisp e alla pseudo variabile this di Javascript. Questo costrutto consente di creare meta-comandi che di fatto sono costrutti del linguaggio
  7. Le caratteristiche precendti consentono, entro certi limiti, di creare linguaggi specifici di dominio in modo quasi naturale.
  8. Era abbastanza veloce se comparato a linguaggi moderni come ruby o python

Purtroppo questi meccanismi hanno generato anche un linguaggio ampiamente vulnerabile alle iniezioni di codice magligno, e complesso da debuggare per la mancanza di una tipizzazione forte (PHP assorbe inconsapevolmente molte delle debolezze di Tcl, a causa del type juggling).
Difatti l’espansione delle variabili rende poco controllabile cosa succede…come per es in

set a pu
set b ts
$a$b "Hello World"

A causa di questo suo dinamismo, non è possibile effettuare grandi verifiche sintattiche, e banali errori di battitura non vengono rilevati finche il codice che li contiene non viene eseguito.

Ma questa sua “mancanza” diventa una forza quando si tratta di estenderlo (vedi questo articolo per un elenco dei punti di forza di tcl, in aggiunta a quello di Antirez)

Altri linguaggi come Python “compilano” il codice in p-code, e quindi sono in grado di rilevare inconsistenze significative come uso di variabili non dichiarate.

Tcl non ha una vera e propria sintassi: il vantaggio è che ogni comando ha la “sua” di sintassi, lo svantaggio è che biosgna avere test di unità di copertura molto robusti

Ousterhout ha profetizzato l’esistenza di una dicotomia (http://en.wikipedia.org/wiki/Ousterhout%27s_dichotomy) tra i linguaggi di programmazione, secondo cui i linguaggi staticamente tipati sarebbero generalmente compilati e progettati per lavorare autonomamente, mentre quelli di scripting sarebbero dinamicamente tipati e con strutture dati più semplici.

Questa dicotomia si può applicare bene ad alcuni linguaggi (bash, tcl) ma inizia a stare stretta ai linguaggi più evoluti (come python, ruby e anche le ultime versioni di perl).

Java nel 1995 (7 anni dopo tcl) è un game changer poiché presenta un linguaggio che:

  1. Offre un sottoinsieme delle caratteristiche del C++
  2. E’ molto poco error prone per la gestione automatica della memoria
  3. Essendo staticamente tipato, costringe a definire in modo esplicito le interfacce. Il cast (simile a quello del C/C++) è un costrutto “safe” perché viene verificato a runtime.
  4. Presenta un modello di sicurezza molto robusto e valido.
  5. Presenta anche un modello di isolamento in package molto solido, e comune ai linguaggi dell’epoca (perl, python, ecc)

Purtroppo Java rappresenta bene la dicotomia di Ousterhout poiché non è ideale come linguaggio di scripting, richiede risorse hardware notevoli anche solo per partire, e serve molto codice per esprimere concetti semplici per la mancanza delle Lambda functions e della possibilità di estenderne la sintassi in qualche modo.

I peccati originali di Java sono stati parzialmente corretti dalla versione 1.5 in poi, ma per mantenere la retrocompatibilità alcuni sui punti deboli sono rimasti. Per esempio i templare che sono stati introdotti non sono efficaci come in C++ poiché devono essere retro compatibili, e quindi non vengono attualizzati realmente. Le funzioni lambda verranno introdotte nel jdk 1.8 ma con un ritardo notevole (18 anni rispetto alla data di nascita del linguaggio)

In compenso ora in Java la reflection è una feature molto usata per scrivere librerie, ed è diventato uno strumento assai efficace per costruire architetture a plugin molto solide.
Per esempio IDE come Eclipse non possono essere fabbricati in Python, Perl o Ruby per lo scarso livello di isolamento di tali linguaggi.
In Java è possibile segregare e proteggersi da errori commessi in singoli plugin-in

Negli ultimi anni stanno nascendo linguaggi derivati da Java che vi si appoggiano sopra alla Java Virtual Machine intesa come architettura applicativa. Nei casi più semplici questi linguaggi si limitano a reimplementare i linguaggi di scripting (JRuby, Jython, Clojure, Javascript Rhino, Ejang…) mentre in altri riscrivono completamente il linguaggio (Scala, Fantom, Gosu, Processing).
La cosa affascinante è che Java sta avendo molto successo in questo (basta guardare il numero di linguaggi censiti in http://en.wikipedia.org/wiki/List_of_JVM_languages) e forse diventerà la sua seconda anima…
La ragione è presero detta: anche una semplice reimplementazione di un linguaggio imperativo in Java da’ benefici notevoli: Java dispone di compilatori in linguaggio macchina molto efficaci, gestori di memoria molto evoluti (tra cui quelli con pause deterministiche come il GC1) e accesso ad API native molto aggressive (I/O nativo, accesso alle istruzioni per la gestione della concorrenza a livello di microprocessore, driver per qualsiasi tipo di DB, supporto anche di sistemi operativi embedded che girano dai cellulari ai set top box)… tutto quello che forse poteva diventare l’ecosistema di tool intorno a Tcl/Tk?…Java ha superato il maestro?…