Polimorfismo

In relazione al paradigma della programmazione orientata agli oggetti, in un precedente articolo abbiamo parlato della ereditarietà dicendo:

Con la tecnica della ereditarietà costruiamo una nuova classe derivata a partire da una classe base da cui verranno ereditate le proprietà e i metodi. La particolarità di questa tecnica è che, se ne dovessimo avere la necessità, potremmo modificare uno o più dei suoi metodi a nostro piacimento specializzando così gli oggetti che creeremo del tipo della nostra classe derivata.

La tecnica di riscrittura dei metodi ereditati prende il nome di override. I metodi, così riscritti, vengono definiti metodi polimorfi.

Il metodo che si intende riscrivere nella classe derivata, deve avere lo stesso nome e la stessa firma del metodo presente nella classe base.

Facciamo ora un esempio per capire un po’ meglio come stanno le cose.

Esempio di un metodo polimorfo

Supponiamo di avere la classe base “pianta” e di creare, a partire da questa, due classi derivate che ne ereditino sia le proprietà che i metodi. Chiameremo queste due classi derivate “albero” e “rampicante”.

Supponiamo ora che nella classe base sia stato dicharato il metodo “sviluppo_radice” che fungerà, come vedremo più avanti, da interfaccia.

A questo punto riscriveremo ad hoc nelle classi derivate il metodo “sviluppo_radice” in modo tale che la chiamata di questo metodo fatta su un oggetto del tipo “albero” si comporti diversamente dalla stessa chiamata fatta su un oggetto del tipo “rampicante”.

Il metodo “sviluppo_radice” sarà quindi un metodo polimorfo, e la sua riscrittura operata nelle due classi derivate sarà stata una operazione di override.

Vantaggi del polimorfismo

Come abbiamo avuto modo di vedere, il polimorfismo ci permette di avere una interfaccia unica verso tutti i possibili altri programmi (definiti programmi client) che useranno le nostre classi derivate.

In questo modo avremo due vantaggi:

  1. Sarà sempre possibile estendere le modalità di risposta ad una stessa chiamata al metodo interfaccia, includendo tutte le possibili dichiarazioni dei metodi polimorfi in una nostra specifica classe contenitore a cui dovranno fare riferimento i programmi client.
  2. Sarà sempre possibile migliorare le modalità di risposta modificando il solo codice contenuto nei metodi polimorfi senza che i programmi client debbano essere modificati.

Esempio di polimorfismo in FreeBASIC

Vediamo ora un piccolo esempio della applicazione del polimorfismo in FreeBASIC.

''Classe base "pianta"
type pianta
  public:
    dim as string nome
    declare constructor(byref _nome as string)
    declare function sviluppo_radice() as string
  protected:
    ''impedisce l'uso del costruttore di default
    declare constructor()
end type
constructor pianta(byref _nome as string)
  this.nome = _nome
end constructor
function pianta.sviluppo_radice() as string
  return "sono una generica radice di una pianta"
end function

''Classe derivata "albero"
type albero extends pianta
  public:
    declare constructor(byref _nome as string)
    declare function sviluppo_radice() as string
end type
constructor albero(byref _nome as string)
  base(_nome)
end constructor
function albero.sviluppo_radice() as string
  return "sono la radice di un albero di"
end function

''Classe derivata "rampicante"
type rampicante extends pianta
  public:
    declare constructor(byref _nome as string)
    declare function sviluppo_radice() as string
end type
constructor rampicante(byref _nome as string)
  base(_nome)
end constructor
function rampicante.sviluppo_radice() as string
  return "sono la radice del rampicante"
end function

''Creazione di un oggetto di tipo "albero"
dim as albero mio_albero = albero("pioppo")

''Creazione di un oggetto di tipo "rampicante"
dim as rampicante mio_rampicante = rampicante("edera")

''Invoca il metodo polimorfo
print mio_albero.sviluppo_radice() & " " & mio_albero.nome
print mio_rampicante.sviluppo_radice() & " " & mio_rampicante.nome

sleep

Bene. Con questo articolo finiamo la sintetica panoramica sulla programmazione ad oggetti in FreeBASIC.

Ora non resta che sperimentare. 😉

Overloading

Oggi discuteremo di un altro importante costrutto specifico del paradigma della programmazione orientata agli oggetti: vedremo insieme cosa si intende per overloading (in italiano: sovraccarico) e come questa tecnica sia implementata in FreeBASIC.

Introduzione

Abbiamo visto nell’articolo introduttivo alla programmazione orientata agli oggetti in FreeBASIC che tra i membri di una classe, oltre alle proprietà ci sono anche i cosiddetti metodi che, in ultima analisi, non sono altro che procedure: ovvero subroutines o funzioni.

Come ben sappiamo ogni procedura è caratterizzata da uno specifico nome, dalla possibilità di ricevere degli argomenti e, nel caso delle funzioni, anche di restituire un valore di ritorno.

La lista degli argomenti viene definita la firma (signature) della procedura.

La tecnica di overloading consiste nello scrivere più procedure aventi lo stesso nome, ma firma differente.

Questa tecnica viene normalmente applicata anche alla procedura costruttore.

Utilità della tecnica di overloading

Arrivati a questo punto è lecito domandarci: ma a che ci serve applicare questa tecnica?

La risposta è semplice:

  • Se sovraccarichiamo un costruttore abbiamo la possibilità di creare degli oggetti (istanze della nostra classe) inizializzandoli in maniera differente.
  • Se sovraccarichiamo un metodo abbiamo la possibilità di specializzare un certo comportamento in base proprio ai parametri passati come argomenti.

Esempio di overloading su un metodo

''definizione della classe "sommatore"
type sommatore
  public:
    ''dichiarazione del metodo "somma" sovraccaricato
    declare function somma(a as integer, b as integer) as integer
    declare function somma(a as string, b as string) as string
  ''dimensionamento della proprietà "etichetta"
  dim as string etichetta = "Il risultato e': "
end type

''definizione delle funzioni "somma"
function sommatore.somma(a as integer, b as integer) as integer
  return a+b
end function
function sommatore.somma(a as string, b as string) as string
  return a+b
end function

''creazione dell'oggetto istanza della classe "sommatore"
dim as sommatore mio_sommatore

''primo caso: somma con valori interi
dim as integer c, d
c = 3
d = 4
print mio_sommatore.etichetta & mio_sommatore.somma(c,d)

''secondo caso: somma con valori stringa
dim as string e, f
e = "3"
f = "4"
print mio_sommatore.etichetta & mio_sommatore.somma(e,f)

sleep ''pausa

Nota: se applichiamo la tecnica di overloading alle procedure che sono dei membri di una classe, non è necessario specificarlo esplicitamente, ma se vogliamo applicarla alle normali procedure, allora è obbligatorio far seguire al nome della procedura la parola-chiave overload, almeno per la prima procedura che si vuole sovraccaricare.

Bene. Un altro piccolo passo è stato fatto. 🙂

Nel prossimo articolo parleremo del concetto di polimorfismo.

Associazione ed Ereditarietà

Con questo nuovo articolo cercheremo di esplorare due importanti concetti della programmazione orientata agli oggetti così come vengono implementati in FreeBASIC:

  • associazione (per composizione o aggregazione)
  • ereditarietà

Introduzione

Quando studiamo un modo per modellare in una classe gli oggetti del mondo reale o astratto con il quale dobbiamo lavorare, è molto probabile che arriveremo ad avere a che fare con classi che sono in relazione con altre classi.

Per scegliere il tipo di relazione che vogliamo stabilire tra le classi, dobbiamo porci la seguente domanda:

  1. Rispetto ad una generica classe base da cui vogliamo partire per creare la nostra classe derivata, quest’ultima, oltre a prevedere le stesse proprietà e gli stessi metodi, dovrà avere la possibilità di adattarli modificandoli?

Se a questa domanda rispondiamo che non abbiamo la necessità di modificare i membri della classe base, allora sceglieremo la tecnica della associazione, mentre se dovessimo avere la necessità di modificarne qualcuno, allora sceglieremo la tecnica della ereditarietà.

Vediamo ora più in dettaglio queste differenti tecniche.

Associazione

In FreeBASIC la tecnica della associazione può essere adottata in due differenti modalità.

Associazione per composizione

Con la tecnica della associazione per composizione possiamo realizzare una classe derivata di una certa complessità a partire da classi base più semplici, ciascuna delle quali manterrà inalterate le sue proprietà e i suoi metodi.

Volendo fare un esempio, potremmo immaginare le varie parti che compongono una pianta: la radice, il fusto, la foglia, il fiore, il frutto.

Ciscuna classe base può essere a sua volta la classe derivata di altre classi base. E così via.

La particolarità della tecnica per composizione è che al momento della distruzione in memoria dell’oggetto del tipo della classe derivata, anche tutti gli oggetti del tipo delle classi base verranno distrutti in quanto di fatto erano contenuti nell’oggetto composto.

Tornando all’esempio della pianta, potremmo dire che, una volta che sia morta, anche le singole parti che la componevano andranno incontro al normale processo di decomposizione.

Associazione per aggregazione

Con la tecnica della associazione per aggregazione realizziamo una classe derivata che ha dei collegamenti con altre classi base di cui sfrutterà le proprietà e i metodi anche in questo caso senza alterarli.

La particolarità della aggregazione è che la classe derivata contiene soltanto dei puntatori alle altre classi base: ciò significa che nel momento in cui distruggiamo in memoria l’oggetto del tipo della classe derivata, gli altri oggetti del tipo delle classi base che erano stati aggregati non vengono distrutti in quanto sono a tutti gli effetti delle entità indipendenti.

Torniamo all’esempio della pianta. Possiamo dire che le classi base, a cui la classe derivata pianta deve associarsi, sono la classe base terra, acqua, sole, aria. In questo caso alla morte della pianta non vi è nessun effetto distruttivo sulle classi base.

Ereditarietà

Con la tecnica della ereditarietà costruiamo una nuova classe derivata a partire da una classe base da cui verranno ereditate le proprietà e i metodi. La particolarità di questa tecnica è che, se ne dovessimo avere la necessità, potremmo modificare uno o più dei suoi metodi a nostro piacimento specializzando così gli oggetti che creeremo del tipo della nostra classe derivata (vedi l’articolo dedicato al polimorfismo).

In FreeBASIC non è prevista la cosiddetta ereditarietà multipla: ovvero la possibilità di creare una classe derivata ereditando le proprietà e i metodi da più classi base.

Ancora una volta prendiamo come esempio la nostra piantina che dovrà necessariamente ereditare le sue caratteristiche e le sue funzionalità da un seme.

Costruiamo una classe derivata

''Classe derivata "pianta"
''  ereditarietà -> la pianta è: un seme
''  composizione -> la pianta ha: radice, fusto, foglia, fiore, frutto
''  aggregazione -> la pianta usa: terra, acqua, sole, aria

''classe base per la ereditarieta'
type seme
  public:
    dim as string nome
    declare constructor(byref _nome as string)
  protected: ''impedisce l'uso del costruttore di default
    declare constructor()
  ''[…]
end type
constructor seme(byref _nome as string)
  this.nome = _nome
end constructor

''classi base per la composizione
type fiore
  public:
     dim as integer numero_fiori
end type
''…

''classi base per l'aggregazione
type terra
  public:
    dim as string tipo
    declare constructor(byref _tipo as string)
end type
constructor terra(byref _tipo as string)
  this.tipo = _tipo
end constructor
''…

''classe derivata "pianta"
type pianta extends seme ''ereditarieta'
  public:
    dim as fiore f ''composizione
    ''…
    dim as terra ptr t ''aggregazione
    ''…
    declare constructor(byref _nome as string, _
                        byref _f as fiore)
end type
constructor pianta(byref _nome as string, _
                   byref _f as fiore)
   base(_nome) '' vedi nota piu' sotto
   this.f = _f
end constructor

''creazione dell'oggetto "mia_pianta" del tipo della classe derivata
dim as pianta mia_pianta = pianta("Non ti scordar di me",type<fiore>(6))
dim as terra ptr t1 = new terra("buona") ''creo un oggetto "terra"
mia_pianta.t = t1 ''aggrego alla pianta l'oggetto "terra"

print "Nome pianta  : " & mia_pianta.nome
print "Numero fiori : " & mia_pianta.f.numero_fiori
print "Tipo terra   : " & mia_pianta.t->tipo


delete t1 ''distruzione dell'oggetto aggregato
mia_pianta.t = 0

sleep

Nota sulla istruzione base

L’istruzione base è una chiamata esplicita al costruttore della classe base ereditata dalla classe derivata. Questa istruzione deve comparire al primo posto nel costruttore in cui viene utilizzata.

Che fatica! Per oggi ci fermiamo qui. 🙂

Nel prossimo articolo discuteremo del concetto di overloading.

Incapsulamento

Nella programmazione orientata agli oggetti, uno dei concetti fondamentali è quello dell’incapsulamento.

Quando definiamo una nostra classe, è bene restringere l’ambito di visibilità delle proprietà e dei metodi ai soli metodi che definiremo pubblici che fungeranno quindi da interfaccia verso il mondo esterno.

Con questa strategia di programmazione abbiamo i seguenti due vantaggi:

  • Possiamo modificare liberamente la logica dei metodi incapsulati senza che queste modifiche alterino il modo con cui altri oggetti si interfacciano con l’oggetto del tipo della nostra classe.
  • Impediamo l’accesso diretto alle proprietà in modo tale possiamo sviluppare del codice di controllo per impedire input non corretti.

Definizione dei diritti di accesso ai membri

In FreeBASIC abbiamo tre diverse tipologie per definire i diritti di accesso (ambito di visibilità) ai membri di una classe (proprietà e metodi):

  1. public: in mancanza di una definizione esplicita da parte del programmatore, public è la classificazione di default. Questa classificazione permette il libero accesso al membro così definito non soltanto da parte di tutti gli altri membri della classe, ma anche dal codice e dalle procedure definite a livello dello stesso modulo: ovvero dello stesso file sorgente.
  2. protected: questa classificazione restringe l’accesso ad un determinato membro di una classe sia ai membri della stessa classe che a quelli di eventuali classi derivate.
  3. private: questa classificazione permette l’accesso ad un membro di una classe solo ed esclusivamente ai soli membri della classe.

Questa tre tipologie di classificazione hanno lo stesso effetto anche per le procedure costruttore e distruttore.

Buone pratiche di programmazione

Quando adottiamo il paradigma della programmazione orientata agli oggetti, in relazione al tema dei diritti di accesso ai membri di una classe sono state consolidate nel tempo delle cosiddette buone pratiche di programmazione che pervedono di adottare queste modalità di definizione del codice:

  • proprietà: è bene classificarle come private.
  • metodi per la logica di funzionamento interna dell’oggetto: è bene classificarli come protected.
  • metodi interfaccia: vengono classificati come public.

Esempio

''definizione della classe strumento_musicale
type strumento_musicale
  public:
    declare sub imposta_strumento(s as string)
    declare function ottieni_strumento() as string
  protected:
    declare function controllo_tipo(s as string) as string
  private:
    dim as string strumento
end type

''implementazione dei metodi della classe strumento_musicale
sub strumento_musicale.imposta_strumento(s as string)
  if controllo_tipo(s) = "OK" then
    this.strumento = s
  else
    this.strumento = "non previsto nella nostra scuola."
  end if
end sub

function strumento_musicale.ottieni_strumento() as string
  return this.strumento
end function

function strumento_musicale.controllo_tipo(s as string) as string
  if s = "chitarra" then
    return "OK"
  else
    return ""
  end if
end function

''crea un oggetto del tipo strumento_musicale
dim as strumento_musicale mio_strumento_musicale
dim as string mio_strumento
input "Qual e' il tuo strumento"; mio_strumento 
mio_strumento_musicale.imposta_strumento(mio_strumento)
print "Lo strumento che hai inserito e': " & _
mio_strumento_musicale.ottieni_strumento()

''una eventuale chiamata diretta al metodo dichiarato
''protected genererebbe, in fase di compilazione, un
''errore di "accesso illegale ad un membro"
''mio_strumento_musicale.controllo_tipo(mio_strumento)

Bene! Abbiamo fatto insieme un altro piccolo passo nel mondo della programmazione ad oggetti.

Nel prossimo articolo vedremo come in FreeBASIC si applicano le tecniche di associazione ed ereditarietà. 🙂

Antroposofia e coding

È possibile immaginare di fare coding antroposoficamente?

Questo articolo non vuole inserirsi nel dibattito se sia corretto o meno avvicinare i bambini al coding, ovvero alla programmazione informatica, durante la scuola primaria con l’obiettivo di sviluppare in loro il pensiero computazionale già nei primi dieci anni di vita.

Anzi, personalmente ho firmato la petizione ai responsabili dell’istruzione nell’UE e negli Stati membri per concedere il diritto ad asili nido, scuole materne e scuole elementari di essere liberi dallo schermo, nella convinzione che ogni cosa deve essere fatta a suo tempo.

Il pensiero computazionale è un processo mentale per la creazione di un algoritmo, ovvero di una sequenza finita di passi elementari (istruzioni), traducibili poi in un linguaggio di programmazione (codice sorgente) in grado di permettere ad un computer di risolvere un problema.

Sull’introduzione delle competenze digitali nella scuola si visiti il sito web del MIUR (Ministero dell’Istruzione dell’Università e della Ricerca) dedicato al Piano Nazionale Scuola Digitale.

Si veda inoltre il progetto CS Unplugged che intende avvicinare i bambini al mondo del coding senza utilizzare direttamente il computer.

L’intenzione è invece quella di esplorare la possibilità, se esiste, di fare coding antroposoficamente così come esiste per esempio un modo antroposofico di educare (pedagogia Waldorf), di coltivare (agricoltura biodinamica) o di curare (medicina antroposofica).

Coding e creatività

Non c’è dubbio che nella programmazione informatica la creatività giochi un ruolo fondamentale.

Non basta infatti conoscere un linguaggio di programmazione per risolvere un dato problema, e molto spesso non basta neanche una disciplinata capacità di analisi unita alla conoscenza della natura del problema che si sta affrontando. Tutte cose, ovviamente, indispensabili.

Quando ci si trova bloccati, quando sembra che non ci sia più una via d’uscita, ecco che una illuminazione, un guizzo della fantasia, una fulminea intuizione, ci fanno scorgere finalmente la soluzione, e soltanto allora possiamo tornare a mettere mano al codice sorgente scrivendo o correggendo il nostro algoritmo.

Quando il pensiero concepisce un algoritmo efficace ed efficiente, lo si descrive spesso come una soluzione elegante, e non è raro sentire accostare a questa soluzione il concetto di bellezza.

Tutto questo ha a che fare con l’ampio tema relativo alla risoluzione dei problemi, il cosiddetto problem solving, che, per inciso, riguarda tutti noi, sia che si stia lavorando nell’ambito informatico, sia che si debba semplicemente decidere come organizzarsi per andare a fare la spesa.

Possiamo quindi dire che il pensiero computazionale, oltre ad essere una facoltà umana di uso generalizzato e quotidiano, è strettamente legato al pensiero creativo.

Arte e Antroposofia

Nell’ambito dell’Antroposofia l’arte riveste un ruolo fondamentale, tanto che si parla di arti antroposofiche.

Se Rudolf Steiner, il fondatore dell’Antroposofia, ha ritenuto che l’intera esperienza umana dovesse venire informata dalla conoscenza spirituale, tanto da influenzare anche la musica, il canto, la poesia, la scultura, la pittura, la danza (euritmia) e persino l’architettura (architettura organica), allora dobbiamo domandarci:

Come possiamo pensare che un’attività umana, oggi così diffusa, come la programmazione informatica, che abbiamo visto essere così legata anche al concetto di creatività, possa rimanere esclusa dalla visione antroposofica?

Come cultori dell’Antroposofia, è forse arrivato il momento di rivolgere la nostra attenzione anche al mondo legato alla programmazione informatica, senza preconcetti, forti anche del fatto che il software è la parte immateriale di questo mondo, la parte più legata al pensiero immaginativo.

“L’informazione è informazione, non materia o energia.” Norbert Wiener

Per cominciare a farlo, si pensi al fenomeno dell’arte digitale o, per esempio, al linguaggio di programmazione Processing che, tra le altre cose, permette di sviluppare opere d’arte generativa.

“[…] ci stiamo avvicinando sempre più all’epoca della composizione consapevole, razionale. Presto il pittore sarà orgoglioso di spiegare che le sue opere sono costruite.” Wassily Kandinsky, Lo spirituale nell’arte

Fare coding antroposoficamente

Se vogliamo provare a mettere in dialogo il mondo dell’Antroposofia con quello del coding occorre forse immaginare nuove applicazioni che siano capaci di toccare lo spirito di chi le usa, e magari spingersi oltre dando vita ad un nuovo paradigma di programmazione che permetta allo spirito dell’autore (il programmatore) di esprimersi.

Un primo possibile passo…

Chi si avvicina all’Antroposofia scopre molto presto l’importanza che in essa riveste il mondo dei colori e delle figure geometriche.

Forse un primo passo potrebbe proprio essere quello di riflettere su come utilizzare i colori e le figure geometriche per creare software antroposofico.

Un piccolo primo esempio: come generare immagini in stile Mondrian.

Mi rendo conto che tutto questo possa apparire come estremamente vago e privo di solide basi, ma si tratta per adesso soltanto di una intuizione su cui magari cominciare a riflettere.

Come lavorare con le proprietà di tipo stringa o array a lunghezza variabile

Nella introduzione alla programmazione ad oggetti in FreeBASIC abbiamo visto cosa sono le proprietà di un oggetto.

In questo nuovo articolo proveremo a scendere un po’ più nel dettaglio per imparare come il compilatore FreeBASIC tratta quel tipo di proprietà che hanno, per loro stessa natura, una lunghezza variabile: ovvero una quantità variabile di spazio di memoria occupato.

Vedremo quindi come lavorare con le stringhe e gli array di tipo variabile (variable-length array).

Lavorare con gli array di tipo variabile

In FreeBASIC le classi sono realizzate attraverso dei tipi di dato definiti da noi (user-defined type o UDT) che devono avere una dimensione fissa.

Nonostante questo, possiamo scegliere come proprietà un array di tipo variabile.

Per farlo dovremo però dichiarare, all’interno della definizione della classe, il nostro array dinamico utilizzando la parola-chiave any.

Questa parola-chiave comunica al compilatore FreeBASIC – come fosse un segnaposto – che le effettive dimensioni dell’array saranno specificate attraverso l’istruzione redim soltanto dopo aver creato un oggetto (istanza della nostra classe).

Esempio con una proprietà stringa e un array di tipo variabile

''definizione della classe
type mia_classe
  ''definizione delle proprietà
  dim as string mia_stringa_variabile
  dim as integer mio_array_variabile(any)
end type

''creiamo un oggetto del tipo della classe definita
dim as mia_classe mio_oggetto

''aggiorniamo la proprietà stringa
mio_oggetto.mia_stringa_variabile = "Oggi e' una bella giornata!"

''aggiorniamo la proprietà array
redim mio_oggetto.mio_array_variabile(1 to 5)

''stampa la stringa
print mio_oggetto.mia_stringa_variabile
''stampa la dimensione dell'array
print str(ubound(mio_oggetto.mio_array_variabile) - _
          lbound(mio_oggetto.mio_array_variabile) + 1)

Nel prossimo articolo vedremo come in FreeBASIC viene implementato il concetto di incapsulamento, tipico della programmazione orientata agli oggetti, per una migliore gestione dell’accesso ai membri di una classe.

Introduzione alla programmazione orientata agli oggetti in FreeBASIC

Ebbene sì! Anche con FreeBASIC possiamo adottare nei nostri programmi il paradigma della programmazione orientatata agli oggetti.

In inglese: object-oriented programming (OOP).

Classe

Il costrutto della classe lo realizzaremo in FreeBASIC attraverso un tipo di dato definito da noi (user-defined type o UDT) che utilizzeremo quindi come modello per creare i nostri oggetti.

Oggetto

Per poter creare un oggetto a partire da una classe – ovvero, in FreeBASIC, dal tipo di dato definito da noi – questa dovrà contenere tra i suoi membri, oltre alle proprietà (variabili, costanti, array, ecc.) e ai metodi (subroutines e funzioni), anche delle particolari procedure chiamate costruttore e distruttore.

Si usa dire che un oggetto è una istanza di una classe.

Costruttore e Distruttore

Quando viene definito un nuovo oggetto, il compilatore FreeBASIC chiamata automaticamente la procedura costruttore di default che inizializza i valori dei parametri dell’oggetto.

Quando invece viene eliminato un oggetto, il compilatore FreeBASIC chiama automaticamente la procedura distruttore che libera le risorse del sistema precedentemente utilizzate dall’oggetto.

Un oggetto viene implicitamente distrutto ogni volta che viene passato per valore in una procedura o quando esce dal suo ambito di utilizzo.

Per dichiarare una certa procedura come costruttore del nostro oggetto utilizzeremo l’istruzione constructor, mentre per la procedura distruttore utilizzeremo l’istruzione destructor.

A differenza delle procedure sub o function, per il costruttore e il distruttore non è necessario specificare alcun nome.

In una classe possiamo specificare più costruttori, ma un solo distruttore.

Quando invece copiamo o creiamo un clone di un oggetto a partire da un oggetto dello stesso tipo il compilatore FreeBASIC crea automaticamente anche il costruttore per la copia o la clonazione.

Queste due tipologie di costruttore possono però anche essere dichiarate e definite dallo stesso programmatore; il quale può, inoltre, anche dichiarare e definire eventuali altri costruttori “specializzati”.

Vediamo ora un po’ più in dettaglio alcune caratteristiche di queste diverse tipologie di costruttori.

Costruttore di default

Il costruttore di default è una procedura che non riceve argomenti e quindi eventuali parametri al suo interno avranno dei valori già impostati da noi o, se non li abbiamo impostati, avranno dei valori di default (p.e. le variabili numeriche avranno valore zero). Questo costruttore viene invocato dal compilatore FreeBASIC appena si definisce un oggetto.

Costruttore per le copie o i cloni degli oggetti

Questo costruttore viene invocato automaticamente dal compilatore FreeBASIC quando viene creato o clonato un oggetto da parte di un altro oggetto dello stesso tipo, oppure quando viene passato ad una procedura per valore (byval). Per dichiarare questo tipo di costruttore occorre che nella dichiarazione sia previsto come argomento un oggetto dello stesso tipo passato per riferimento.

Costruttore “specializzato”

Come programmatori, possiamo definire uno o più di questo tipo di costruttore quando, per esempio, abbiamo la necessità di passare dei valori specifici come argomenti in fase di creazione dell’oggetto.

Esempio dei tre tipi di costruttore e del distruttore

type poligono_regolare
  declare constructor
  declare constructor(byref p as poligono_regolare)
  declare constructor(n as integer)
  declare destructor
  dim numero_lati as integer
end type

''definizione della procedura costruttore di default
constructor poligono_regolare
  numero_lati = 3
end constructor

''definizione della procedura costruttore per le copie o i cloni
constructor poligono_regolare(byref p as poligono_regolare)
  numero_lati = p.numero_lati
end constructor

''definizione della procedura per un costruttore "specializzato"
constructor poligono_regolare(n as integer)
  numero_lati = n
end constructor

''definizione della procedura distruttore
destructor poligono_regolare
  ''istruzioni per la distruzione (vedi istruzione delete) per esempio
  ''di eventuali altri oggetti utilizzati all'interno dell'oggetto.
end destructor

Proprietà

Come abbiamo visto, a partire da una classe possiamo creare (istanziare) più oggetti. Quando creiamo degli oggetti, è molto probabile che ci interessi caratterizzarli con differenti proprietà. Rimanendo nell’esempio della classe “poligono_regolare”, magari vorremmo creare diversi poligoni regolari (oggetti) con la proprietà “colore” differente. Nella programmazione ad oggetti è bene mantenere privato l’ambito di utilizzo delle proprietà: in modo tale che non sia possibile accederci direttamente dall’esterno. Per modificarne il valore, o per leggerlo, scriveremo delle procedure ad hoc che ci garantiscano anche un maggior controllo sull’input dell’utente e sul tipo di output.

Esempio sulle proprietà

type poligono_regolare
  ''[...]
  declare property colore(byref c as ulong) ''per impostare il valore del colore
  declare property colore() as ulong ''per ottenere il valore del colore
  private:
    dim mio_colore as ulong
end type

property poligono_regolare.colore(byref c as ulong)
  this.mio_colore = c
end property

property poligono_regolare.colore() as ulong
  return this.mio_colore
end property

Nota sul parametro this

Nell’esempio riportato più sopra abbiamo fatto uso della parola-chiave this.

Questa parola-chiave è un argomento nascosto passato per riferimento che funge appunto da riferimento ad uno specifico oggetto (ovvero alla specifica istanza di una classe). Questo riferimento viene automaticamente passato a tutti i membri dichiarati nella classe: costruttori, distruttore, proprietà, metodi (subroutines e funzioni) in modo tale che le loro definizioni potranno agire su quello specifico oggetto.

Metodi

Come per i costruttori e il distruttore, anche per i metodi, che in ultima analisi non sono altro che delle procedure di tipo sub o function, occorre che siano dichiarati all’interno della classe e definiti all’esterno.

Esempio di metodi

type poligono_regolare
  ''[...]
  declare sub angolo_al_centro(n as integer)
  declare function tipo(n as integer) as string
  ''[...]
  dim angolo as long
end type

sub poligono_regolare.angolo_al_centro(n as integer)
  angolo = 360/n
  print "Angolo al centro: "; angolo
end sub

function poligono_regolare.tipo(n as integer) as string
  select case n
    case 3
      return "triangolo equilatero"
    case 4
      return "quadrato"
    case 5
      return "pentagono regolare"
    case else
      return "non gestito"
  end select
end function

Come creare un oggetto e una sua copia

Ora che abbiamo le basi per scrivere una classe, vediamo come creare il nostro primo oggetto e come da questo fare una sua copia.

''Definisce la CLASSE
type poligono_regolare
  declare constructor() ''costruttore di default
  declare constructor(byref p as poligono_regolare) ''costruttore per copia/clone
  declare property numero_lati(byref n as integer) ''per impostare/cambiare
                                                   ''il numero dei lati
  declare property numero_lati() as integer ''per ottenere il numero dei lati
  private:
    dim num_lati as integer
end type

constructor poligono_regolare
  num_lati = 3
end constructor

constructor poligono_regolare(byref p as poligono_regolare)
  num_lati = p.num_lati
end constructor

property poligono_regolare.numero_lati(byref n as integer)
  this.num_lati = n
end property

property poligono_regolare.numero_lati() as integer
  return this.num_lati
end property

''------------------------------

''Dimensiona e crea un nuovo OGGETTO (una istanza della CLASSE)
dim poligono_a as poligono_regolare
print poligono_a.numero_lati ''stampa il valore di default 3
poligono_a.numero_lati = 6 ''cambia il numero dei lati

''Crea una copia
dim poligono_b as poligono_regolare
print poligono_b.numero_lati ''stampa il valore di default 3
poligono_b = poligono_a ''crea la copia
print poligono_b.numero_lati ''stampa il valore 6

Bene! Come introduzione alla programmazione orientata agli oggetti in FreeBASIC possiamo fermarci qui. 🙂

Nel prossimo articolo vedremo come lavorare con le proprietà di tipo stringa o array a lunghezza variabile.

Arte generativa con FreeBASIC

Tutti sanno che nell’ottobre del 1917 ci fu una rivoluzione.

Fu proprio in quel mese, infatti, che uscì il primo numero della rivista Lo stile intorno alla quale si sviluppò il movimento artistico del neoplasticismo. Movimento che nel campo della pittura si basava su principi astratti e geometrici. Proprio per questo si fa riferimento al neoplasticismo anche definendolo astrattismo geometrico.

Tra i fondatori della rivista e del movimento ci fu il pittore Piet Mondrian le cui opere più famose sono composizioni dove compaiono soltanto linee nere orizzontali o verticali che dividono la tela in figure geometriche rettangolari o quadrate, alcune delle quali – la minoranza – sono colorate utilizzando soltanto i colori primari (rosso, giallo e blu). Molte parti, quindi, rimangono bianche.

Ma questo blog non parla di coding e del linguaggio di programmazione FreeBASIC? Cosa c’entra dunque l’arte?

In realtà esiste un elemento in comune tra queste due forme di espressione umana: la creatività.

Sebbene la creatività interessi molte fasi del ciclo della produzione del software (per esempio quella relativa al problem solving), qui vorrei concentrarmi soltanto su uno specifico campo di applicazione dello sviluppo del codice che è quello della cosiddetta Arte generativa: ovvero scrivere del codice che in maniera autonoma, o semi-autonoma, generi delle opere d’arte.

Generatore di immagini in stile Mondrian

Questo blog ha un taglio molto pratico e quindi vediamo subito insieme un esempio di come creare un piccolo programma in FreeBASIC che generi in maniera casuale – e quindi autonoma – delle immagini che richiamino almeno in parte lo stile di Mondrian.

Algoritmo

Ecco in sintesi i passi del nostro algoritmo:

  • Creare una finestra con l’istruzione screenres.
  • Inserire all’interno di un ciclo do-loop il codice per raccogliere l’input dell’utente attraverso l’istruzione getkey e poi con la struttura di controllo select case discriminare la prosecuzione delle operazioni:
    • In un caso disegnare le figure con l’istruzione line le cui dimensioni e colore sono definiti in maniera aleatoria attraverso l’istruzione rnd che genera un numero pseudo-casuale basato sull’algoritmo Mersenne Twister.
    • Nell’altro uscire dal programma.

Codice sorgente

''project:     fb_mondrian.bas
''license:     GNU GPL v3
''version:     beta
''date:        September 20, 2020
''description: Mondrian style images generator
''author:      Luca Evangelisti
''web:         https://ciucoinformatico.home.blog/

dim as long key ''key entered

dim w as integer ''width of canvas
dim h as integer ''height of canvas

declare sub draw_image(w as integer, h as integer)

''canvas's size
w = 1000
h= 617

screenres w, h, 32
windowtitle("fb_mondrian.bas | Mondrian style images generator")

''color:
'' foreground: black
'' background: white
color(rgb(255,255,255),rgb(0,0,0))
cls

'menu
print "Press <Enter> to generate the image."
print "Press <Esc> to exit the programme."

''seeds the random number generator
randomize

do
  key = getkey

  select case key
    case 13 ''carriage return
      cls
      draw_image(w, h)
    case 27 '' quit
      exit do
    case else ''none
  end select

  ''to avoid unwanted or repeated characters,
  ''this loop works until the inkey buffer is empty
  while inkey <> "": wend
loop

''draws image
sub draw_image(w as integer, h as integer)
  dim free_w as integer '' free width
  dim free_h as integer ''free height
  dim as integer fill_color
  dim as integer x1, y1, x2, y2 = 0
  dim as integer margin = 10
  free_w = w
  free_h = h
  do
    y2 = int(rnd * h) + y1
    do
      x2 = int(rnd * w) + x1
      fill_color = int(rnd * 8) + 1
      select case fill_color
        case 1 ''yellow
          line(x1,y1)-(x2,y2),rgb(255,255,0),BF
        case 2 ''red
          line(x1,y1)-(x2,y2),rgb(255,0,0),BF
        case 3 ''blue
          line(x1,y1)-(x2,y2),rgb(0,0,255),BF
        case 4 to 8 ''white
          line(x1,y1)-(x2,y2),rgb(255,255,255),BF
        case else
      end select
      x1 = x2 + margin
    loop until x2 > w
    x1 = 0
    y1 = y2 + margin
  loop until y2 > h
end sub

Provate pure liberamente a modificarlo.

Ciao e al prossimo articolo. 🙂

CLUMSY beta version

Good news! 🙂

CLUMSY si arricchisce delle classiche funzionalità taglia (cut), copia (copy) e incolla (paste).

CLUMSY è un semplice editor di testo multipiattaforma per la console (o emulatore di terminale). In ambienti Windows tipicamente si indica la console con il termine “Prompt dei comandi”, mentre in ambienti GNU-Linux con “Terminale”. CLUMSY permette inoltre di compilare direttamente un file sorgente .bas utilizzando il compilatore FreeBASIC, e mandare quindi in esecuzione il file eseguibile. CLUMSY è distribuito sotto i termini della Licenza GNU General Public License versione 3. Licenza che permette di ridistribuire e modificare il codice sorgente liberamente. CLUMSY è scritto in FreeBASIC.

Ci sono però delle limitazioni, neanche tanto piccole. 😉

  • Cut (F6) taglia una sola linea di codice e la elimina per intero (occhio!).
  • Copy (F7) idem con patate: ovvero copia un’intera e sola linea di codice.
  • Paste (F8) incolla la linea di codice precedentemente selezionata con la funzione F6 o F7.

Oltre questo, CLUMSY è un programma vecchio stile, dove l’uso del mouse è stato volutamente escluso (sigh!).

Clumsy è un termine della lingua inglese. Traducendolo in italiano si ottiene l’immagine di una persona maldestra o di un oggetto mal costruito. 🙂

Lo scopo di CLUMSY è però semplicemente quello di testare velocemente piccole porzioni di codice FreeBASIC, giusto per impratichirsi con questo linguaggio di programmazione senza dover perdere troppo tempo con un IDE (Integrated Development Environment) decisamente più serio e potente di cui si avrà bisogno una volta che si dovrà scrivere un programma di una certa complessità.

Potete scaricare i files sorgenti di CLUMSY qui.

Ecco anche un breve video introduttivo a CLUMSY.

Buon coding! 🙂

Vittorio Albertoni, Intramontabile BASIC

Tempo fa, giracchiando qua e là per il Web, mi sono imbattuto sul sito di Vittorio Albertoni ed è stata una piacevole scoperta.

Vittorio è un vero appassionato della tecnologia informatica (information technology) e i suoi articoli hanno il pregio di essere sintetici, chiari e molto accurati.

In particolare volevo segnalarvi l’articolo Intramontabile BASIC che contiene anche un link ad una utilissima Introduzione al linguaggio FreeBASIC (il documento è liberamente scaricabile, stampabile e distribuibile).

Buona lettura… 🙂