Articoli Manifesto Tools Links Canali Libri Contatti ?
Linguaggi / Ruby

Ruby, un'introduzione (ovvero: Programming should be Fun)

Abstract
Ruby è un linguaggio general purpose, completamente orientato agli oggetti, che sta conoscendo un periodo di eccezionale crescita. In questo articolo ne introduciamo le caratteristiche basilari, cercando di spiegare perché la programmazione in ruby non sia solo efficiente, ma addirittura piacevole.
Data di stesura: 08/05/2003
Data di pubblicazione: 26/05/2003
Ultima modifica: 04/04/2006
di Gabriele Renzi Discuti sul forum   Stampa

In collaborazione con Gruppo Utenti Ruby Italia

Io ricordo ancora, a distanza di anni, il mio primo programma, era

10 print "pippo"
20 goto 10

E girava su un c64 nel lontano 1988. Ricordo l'emozione provata: quel senso di creazione, di capire il funzionamento di qualcosa, tutta quella potenza in due sole righe! Cercate di capirmi, avevo otto anni, ed era la prima volta che provavo il piacere della programmazione.

Nella vita reale però ci si trova ad usare strumenti reali, non giocattoli, ed alla lunga, perdiamo questo piacere. Siamo spesso li a sbattere la testa su una free() o una strcat() mal gestite che mandano all'aria un sistema apparentemente perfetto, o imprechiamo per dover scrivere

System.out.println(myObj.toString());

piuttosto che il print che avremmo usato a 8 anni.

Se vi riconoscete, almeno minimamente in questa frustrazione, forse ruby è il linguaggio che fa per voi.

Ruby nasce in Giappone grazie a Yukihiro Matzumoto (Matz, per tutti) nel 1994 (la release 1.0 è del 1996) basandosi su pochi concetti semplici ma nel loro piccolo "rivoluzionari", che illustreremo tra poco.

L'essere sviluppato originariamente nel paese del Sol Levante ha ridotto la visibilità del linguaggio per qualche tempo, poiché la base di programmatori originaria tende a scrivere nella propria lingua, poco nota altrove.

Ovviamente avere una base di sviluppatori che scriva "nativamente" in una lingua diffusa come l'inglese ha permesso ad altri linguaggi di diffondersi in minor tempo, mentre ruby ha impiegato parecchio a valicare i proprio confini originari (all'interno dei quali è diffusissimo, basti pensare che in Giappone sono stati pubblicati l'anno scorso quasi trenta libri su ruby).

Ormai però la comunità di sviluppatori e la letteratura di lingua inglese ha raggiunto la massa critica, e di conseguenza la visibilità (e lo sviluppo del linguaggio) sono in crescita velocissima.

È interessante notare che Il progetto originario è stato variato pochissimo nel tempo (sostanzialmente con la sola introduzione di variabili di classe, poetry mode per le chiamate a metodi, e statement modifier in stile perl), indice che il design iniziale era comunque molto valido.

Ma torniamo alle "spinte ideologiche" dietro il linguaggio. Matz nel progettare ruby ha puntato su pochi concetti fondamentali:

  • un linguaggio dovrebbe far concentrare sul risolvere il problema non su come spiegare al compilatore il modo di risolvere il problema
  • un linguaggio dovrebbe aiutare il programmatore a non fare errori
  • un linguaggio dovrebbe permettere di automatizzare qualsiasi compito banale

Matz si auto-definisce un "language maniac", la sua passione per il design di vari linguaggi di programmazione ha generato ruby come una summa di approcci considerati utili o interessanti provenienti da sistemi anche molto diversi tra loro.

Alcune delle caratteristiche di Ruby

Interpretato

Ciò permette di evitare tempi morti per la compilazione, e problemi di portabilità del codice.

Ovviamente il lato negativo di questo approccio è una minore efficienza del codice.

Per ovviare a questo, Ruby fornisce un sistema di interfacciamento con C/C++ molto semplice ed efficiente,

dunque è possibile usare librerie C esistenti, o riscrivere le parti meno efficenti delle proprie applicazioni in maniera che raggiungano prestazioni migliori.

Inoltre, a detta di molti l'interfaccia verso il C di Ruby è una delle più potenti ed intuitive, rendendo la programmazione di moduli in C simile a quella in Ruby stesso.

Completamente Object Oriented

Ormai da tempo si è imposto l'uso della progettazione ad oggetti per ottenere codice facilmente testabile, manutenibile e di miglior comprensione. Ruby ha un approccio alla OOP ispirato a Smalltalk, e più puro rispetto a Python, C++ e persino rispetto a Java. Non esistono tipi base che non siano oggetti in ruby (pensate a int/Integer in Java), e persino un normale numero inserito da tastiera viene considerato un oggetto e possiede i propri metodi:

  1. 5.times do 
  2.  print "Mi piacciono gli oggetti!" 
  3. end 

Un approccio di questo tipo permette una estrema coerenza e prevedibilità del linguaggio, togliendo al programmatore il peso di dover sapere di volta in volta con cosa stia lavorando, e dunque come debba farlo.

Gestione strutturata delle eccezioni

I linguaggi moderni (Java, Python, C# ...) fanno tutti uso di variazioni sul tema di prova()..solleva(miaEccezione)..recupera(TipoEccezione) poiché ciò permette di isolare la normale logica di controllo da quella dedicata al recupero da situazioni impreviste.

In linguaggi che ne sono sprovvisti, come il C , ci si trova costretti ad un controllo continuo su ogni chiamata a funzione suscettibile di fallimento, intrecciando continuamente le due cose e rendendo meno leggibile il codice.

Ad esempio usando C su UNIX avremmo cose del genere:

  1. /* normale codice */ 
  2.  
  3. if (chiamataSistema() == -1 ) { 
  4. 	if (errno!= EINTR) { 
  5. 		/* gestione errore 1 */ 
  6.  
  7. /* altro codice normale */ 
  8.  
  9. if (altrasyscall() == 0) { 
  10. 	/* gestione errore 2 */ 
  11.  
  12. /* resto del codice */ 

In ruby faremmo una cosa del genere:

  1. codice e syscall 
  2. rescue SystemCallError 
  3.  gestione eccezione 

Sintassi minimale

Avere una sintassi semplice permette di apprendere il linguaggio in breve tempo, e allo stesso tempo permette a qualsiasi sviluppatore di comprendere codice scritto da altri.

L'idea è che non si debbano aggiungere regole sintattiche per tappare sempre nuovi buchi, ma eliminare le debolezze che rendono tali regole necessarie.

Una sintassi ristretta , ma ben progettata, permette al linguaggio di "auto-espandersi" rimanendo sempre simile a se stessa, ad esempio sono stati implementati "in Ruby" le assertion per le suite di Test e delle versioni basilari di design by contract, pur non essendo previsti dall'inizio.

Esiste persino un progetto per usare Ruby come HDL.

Variabili non tipizzate, ma strong typed

Per evitare la confusione derivante dal weak typing ruby mantiene il tipo dei dati in memoria, pur considerando le variabili come dei semplici riferimenti ad oggetti, e quindi senza tipo.

Spesso chi proviene da linguaggi come Java o C++ pensa che questo approccio (comune a molti linguaggi interpretati) sia causa di continui problemi, problemi che in linguaggi con variabili tipizzate possono essere risolti in fase di compilazione, piuttosto che restare latenti.

In effetti però basta pensare all'uso in Java di una HashMap o di Vector per comprendere come questa ipotesi sia errata.

Buona parte del codice scritto è soltanto un continuo cast da e verso Object, che con linguaggi come python o ruby è del tutto inutile:

Miaclasse mia  = (Miaclasse) mioVector.elementAt(10)

Inoltre, il compilatore non può garantirci che l'elemento restituito sia effettivamente di classe Miaclasse, in quanto la collezione su basa su Object. Dobbiamo quindi porre un controllo per assicurarci che l'oggetto restituito sia convertibile con un cast a Miaclasse.

In realtà, quello che stiamo facendo è cercare una soluzione ad un problema generato dal fatto stesso di avere variabili con tipo.

In ruby sarebbe bastato fare

mia = array[10]

(gli array in ruby sono dinamici come i Vector in java)

La scelta di far esistere variabili parametriche, ad esempio nei template del C++ (e forse in java 1.5 ?) può essere vista come un modo per aggirare le limitazioni di variabili con tipizzazione statica.

Sul dualismo weak/strong typing può essere interessante leggere [2] ed il thread che parte qui [3].

È inoltre da notare l'esistenza di una libreria che permette di avere una certa forma di strong typing anche in ruby [4].

Garbage Collection automatica

Sebbene molti ancora storcano il naso al riguardo, l'uso di una GC automatica non è meno efficiente di una gestione manuale della memoria, non a caso moltissimi linguaggi negli ultimi anni hanno fatto una scelta di questo tipo : VB, C#, Java, Perl, per dirne alcuni. Esistono anche esempi di grosse applicazioni che fanno uso di librerie per la GC automatica in C, ad esempio X11 [5].

Classi/funzionalità di base potenti ed integrate

Ad esempio l'integrazione di espressioni regolari, Hash/dizionari, Array dinamici, thread in userland, pattern comuni come Delegate, Observer, Visitor/Iterator, Singleton, Decorator, Introspection, ... integrati direttamente nel linguaggio o in moduli appositi della libreria standard.

POLS e syntax sugar

Probabilmente è il concetto fondamentale dietro Ruby è, quello relativo a POLS e syntax sugar.

POLS sta per Principle Of Least Surprise ed indica la scelta di rendere l'intero sistema ruby coerente e prevedibile: tutto è un oggetto, i metodi hanno nomi ovvii ed auto-esplicativi e la maggior parte delle funzionalità che ci si aspetta che esistano ... beh, esistono :-)

Ad esempio, come ordinare un array? basta un array.sort

Come fare a definire classi/metodi in maniera condizionale?

if condizione
 definizione
end

Inoltre ci vengono fornite molte delle funzionalità a cui si è abituati in altri linguaggi; chi provenisse dal C++ potrebbe desiderare di usare l'operatore "<<" per l'output.

Ruby fornisce dunque un metodo "<<" per gli oggetti IO implementato in maniera da modificare l'oggetto e restituirlo di nuovo. In questa maniera è possibile scrivere:

out << "ciao" << " a "  <<"tutti!"

semplicemente facendo riferimento ad un metodo dell'oggetto IO, ma senza rendersene conto.

Il syntax sugar rappresenta invece la scelta da parte dei progettisti di permettere una scrittura naturale senza rovinare la natura OO del linguaggio. Un esempio è l'esistenza dei vari operatori, come "+,-,*,<,==,<=>" etc.

In realtà si tratta di metodi definiti nelle rispettive classi, invocabili però senza la sintassi classica obj.metodo.

L'eleganza di questo approccio è evidente se si pensa a come il metodo "+" possa essere usato per lavorare su Integer, Float, String, Array ed altre classi, lasciando alla classe il compito di gestirne il comportamento.

Un esempio collegato è l'esistenza di una sintassi

a+=b

per

a=a+b

Ruby si preoccupa di definire per noi il comportamento dell'assegnazione "+=" (e "*=" , "%=" etc.) nel momento in cui definiamo l'operazione "+"

Il concetto che si individua dietro questi approcci è pervasivo in ruby ed è la caratteristica che veramente lo distingue da altri linguaggi: rendere semplice la vita del programmatore.

Su questa stessa logica si basa anche l'esistenza degli iteratori, dei blocchi/lambda, dei singleton method e dei mix-in, ma di questo parleremo nella seconda parte, se avrete la voglia di leggerci ancora.

Informazioni sull'autore

Gabriele Renzi, studente di Ingegneria Informatica, è un appassionato di programmazione e sistemi operativi. Scrive "hello world" in una dozzina di linguaggi ma non riesce ad andare oltre nemmeno in uno.
Collabora con il Progetto Documentazione Italiana FreeBSD ed è membro del Gruppo Utenti Ruby Italia.

È possibile consultare l'elenco degli articoli scritti da Gabriele Renzi.

Altri articoli sul tema Linguaggi / Ruby.

Risorse

  1. Parte 2: Ruby, un'introduzione (ovvero: Programming should be Fun) (seconda parte)
    http://www.siforge.org/articles/2003/06/28-ruby-intro-2.html
  2. Strong versus Weak Typing.
    http://www.artima.com/intv/strongweak.html
  3. Forum coi commenti sull'articolo di Guido van Rossum su "Strong vs. Weak Typing".
    http://www.ruby-talk.org/blade/64602
  4. Strong Typing module for Ruby.
    http://www.nwlink.com/~rpav/StrongTyping.html
  5. GC FAQ -- draft, folk myths, folk truths, tradeoffs, ...
    http://www.iecc.com/gclist/GC-faq.html#Folk%20myths
  6. Il sito ufficiale del linguaggio Ruby.
    http://www.ruby-lang.org/
  7. Ruby User Group Italia.
    http://ada2.unipv.it/ruby/
  8. Ruby Central.
    http://www.rubycentral.org
  9. Ruby Garden.
    http://www.rubygarden.org/
Discuti sul forum   Stampa

Cosa ne pensi di questo articolo?

Discussioni

Questo articolo o l'argomento ti ha interessato? Parliamone.