[incr Tcl]

« Tk: Descrizione di un demo Tk: ixsetAppunti di Tcl/TkPrimo incontro con classi e oggetti »

Programmazione Object-Oriented

La programmazione orientata agli oggetti (Object Oriented Programming, in breve OOP) è uno stile di programmazione che deriva da quello classico procedurale, e può essere considerato una sua estensione. Consiste essenzialmente nella creazione di strutture dati gerarchiche e combina i dati insieme alle operazioni che li manipolano. Il paradigma OO è utile soprattutto nella strutturazione di programmi di grandi dimensioni. Se correttamente usato, può rendere un programma maggiormente comprensibile e le sue parti facilmente riutilizzabili in altri contesti; può inoltre facilitare le modifiche e la manutenzione, prevenire molti errori e semplificare il debugging per quelli che non si sono potuti evitare.

Le principali estensioni di Tcl per la programmazione object-oriented sono:

OTcl
Abbreviazione di MIT Object Tcl. Si tratta di una estensione di Tcl compatta, potente, e portabile, distribuita sotto la licenza open-source MIT.
[incr Tcl]
Estensione ad oggetti di Tcl simile al C++, anche nel nome, infatti [incr Tcl] è il comando Tcl che incrementa di uno la variabile Tcl, così come C++ è il comando, nel linguaggio C e derivati, che incrementa di uno la variabile C. Si legge come "increment tickle" oppure "inker tickle" ed è anche noto col nome semplificato itcl.
snit
Acronimo ricorsivo di Snit's Not Incr Tcl. La sua caratteristica principale, che la rende molto flessibile, è che è basata non sull'ereditarietà ma sulla delegazione.

Descriveremo solo [incr Tcl], in quanto è una delle più usate. È su questa che si basa una estensione ad oggetti di Tk, [incr Tk], che a sua volta è stata usata per costruire una popolare libreria di widget (più complessi ed ad alto livello rispetto ai widget Tk, ma basati su quest'ultimi), la [incr Widgets].

In Tcl puro non ci sono meccanismi sufficientemente potenti per creare nuove strutture dati o librerie di codice riusabili senza ricorrere al C. [incr Tcl] aggiunge questi meccanismi, mantenendo per altro la stessa semplice sintassi di Tcl e garantendo la compatibilità di tutto il codice Tcl preesistente che non fa uso di questa estensione (così come il C++ è retro-compatibile con il C).

Superare lo scetticismo iniziale

Chi si avvicina per la prima volta alla programmazione OO, pur avendo notevole esperienza nella programmazione tradizionale, trova spesso delle difficoltà ad accettare prima e poi a recepire ed utilizzare il nuovo paradigma, in quanto è spesso difficile cambiare abitudini ben consolidate.

Ad una analisi superficiale sembra che la sola differenza tra i due paradigmi stia nella nomenclatura e nella sintassi (come ad esempio nel fatto che dati e funzioni si definiscono insieme anzichè separatamente). L'essenza della programmazione OO e il suo rapporto con la programmazione tradizionale non viene capito o viene frainteso.

Una delle principali ragioni per cui molti programmatori sono restii ad accettare il paradigma OO sta a mio parere nel fatto che spesso la programmazione OO viene presentata in modo antitetico rispetto a quella procedurale, mentre invece credo sia importante sottolineare che si tratta della sua evoluzione naturale e non vi è alcuna soluzione di continuità.

Lo dimostra il fatto che, in linea di principio, si può programmare ad oggetti anche in un linguaggio che non lo è, ma che sia sufficientemente generale come il C o il Pascal. Per avere maggiori dettagli su questo punto consiglio la lettura di un convincente articolo di Paul Field datato 1991, ma ancora sorprendentemente attuale, intitolato proprio Object-oriented programming in C.

Nel paragrafo Esempio: la classe pack ho riscritto in [incr Tcl] l'esempio presentato in questo articolo, in modo che i programmatori C possano confrontarlo con la versione C riportata nell'articolo stesso.

I tre aspetti della programmazione OO sono incapsulazione, ereditarietà e polimorfismo. L'articolo di Paul si concentra solo sull'incapsulazione, ma non è difficile capire come anche l'ereditarietà e persino l'aspetto più complesso e innovativo della OOP, il polimorfismo, possano essere implementati in C! L'ereditarietà corrisponde al nesting esplicito delle structure in C. Il polimorfismo si ottiene implementando esplicitamente il meccanismo del late-binding proprio come fa un compilatore C++ con le funzioni virtuali. Questo consente di scrivere codice generico che assume poi un significato preciso a seconda del tipo più specifico dell'oggetto su cui si opera, come vedremo meglio in seguito.

Questo non vuole essere un argomento a favore della programmazione OO in un linguaggio non ad oggetti. In pratica questo questo modo di fare non è conveniente, ma è solo servito a mostrare come non c'è niente di magico o miracoloso nella programmazione ad oggetti, come spesso purtroppo è stata pubblicizzata.

Anzi la programmazione ad oggetti non è affatto un modo totalmente nuovo di fare le cose, ma piuttosto una mentalità derivata da esperienze maturate nel campo della programmazione procedurale.

Probabilmente voi stessi avete almeno qualche volta utilizzato senza rendervene conto, i tre concetti chiave della programmazione ad oggetti (incapsulazione, ereditarietà e polimorfismo), pur non programmando ad oggetti.

Inoltre vi sono molti aspetti (di cui parleremo in seguito) in librerie classiche non ad oggetti, come Tk o la libreria di I/O standard del C che le rendono parzialmente "orientate agli oggetti", nonostante siano state scritte in C. Più precisamente si dice che queste librerie sono basati sugli oggetti (object-based), e non sono pienamente orientate agli oggetti (object-oriented).

Programmare ad oggetti vuol dire solo applicare sistematicamente e consapevolmente i tre aspetti chiave prima menzionati (incapsulazione, ereditarietà e polimorfismo), supportati da una sintassi adeguata e linguaggi e relativi interpreti e compilatori che offrono costrutti adatti ad implementarli in modo semplice ed efficiente.

Un altro motivo per cui molti programmatori sono restii ad adottare la OOP è che temono di dover essere costretti a riscrivere tutto il codice e le librerie che finora hanno prodotto. È perfettamente lecito voler riusare codice legacy e librerie preesistenti e, anche nel caso in cui si debba sviluppare nuovo codice, non è detto che si debba utilizzare sempre e dovunque il paradigma OO al posto di quello procedurale e non convenga piuttosto una soluzione mista.

La risposta a questi interrogativi è di scegliere linguaggi ad oggetti non puri, che mantengono la compatibilità e, permettendo di mischiare i due paradigmi, consentono un passaggio graduale da un paradigma all'altro, laddove opportuno. Ad esempio se avete delle buone librerie C che volete riutilizzare, C++ probabilmente è la scelta migliore, in quanto vi permette di riutilizzarle quasi così come sono, riducendo al minimo la necessità di modifica.

« Tk: Descrizione di un demo Tk: ixsetAppunti di Tcl/TkPrimo incontro con classi e oggetti »