* Primitive principali
** def_class
*** Definizione
-Definisce la struttura di una classe, dato:
-- un nome
-- una lista di genitori
-- una lista di `field`/`metodi`
-
-Per definire la def_class si inseriscono variabili
-che rappresentano ed i metodi che definiscono il comportamento
-della classe.
+Definisce una classe dato un atomo rappresentante il nome della classe,
+una lista possibilmente vuota di /genitori/
+(/classi definite in precedenza da cui ereditare/) e un'opzionale lista
+contenente la definizione di proprietà nella forma
+/field(name, value, type)/ oppure /field(name, value)/ e la definizione
+di metodi nella forma /method(name, args, body)/.
+
+In particolare il corpo di un metodo della classe deve essere dato in
+forma normale congiunta.
+
+Il risultato della definizione della classe è la semplice aggiunta,
+tramite /assert*/, alla base di conoscenza delle clausole dinamiche:
+- /is_class/ per affermare che l'atomo è il nome di una classe definita
+- /is_child_of/ per creare una gerarchia di classi
+ (/utile nel controllo dei tipi/)
+- /is_member/ per specificare che fields e methods appartengono
+ alla classe /ClassName/
+
+In caso di errori durante la definizione della classe, è necessario
+rimuovere tutte le informazioni rimaste nella base di conoscenza
+riguardanti la classe /ClassName/ prima di restituire un fallimento.
*** Implementazione
#+begin_src prolog :tangle oop.pl
** make
*** Definizione
-Istanzia una classe dato:
-- il nome dell'istanza
-- la classe da istanziare
-- una lista di `assegnamenti`
-
-Sostanzialmente craiamo il costruttore della classe.
-
-Prima di creare l'istanza si controlla che l'atono non sia
-già un'istanza di una classe.
-Se esiste non si procede con l'operazione, in quanto rindondante,
-in caso contrario si passa alla creazione effettiva dell'istanza.
-
-Dopo di che:
-- Se non viene dato il campo /Fields/ allora si crea un
- istanza con i valore di default della classe.
-- Se abbiamo il campo /Fields/ associamo ai fields dell'istanza i valori
- di default e successivamente quelli presenti in /Fields/.
-- Se fallisce la creazione dell'istanza si elimanano le eventuali
- informazioni residue dalla base di conoscenza.
-
+Questo predicato svolge 2 compiti fondamentali in base a cosa gli viene
+dato in ingresso.
+
+**** Definizione di un'istanza
+Dato un atomo rappresentante il nome dell'istanza da creare, un atomo
+rappresentante una classe *necessariamente* definita in precedenza ed
+un'opzionale lista di "assegnamenti" a field della classe,
+crea l'istanza /InstanceName/.
+
+Come per la [[*def_class][definizione di una classe]] ciò avviene tramite modifiche
+alla base di conoscenza utilizzando i predicati dinamici:
+- /is_instance/ per affermare che l'atomo /InstanceName/ è un'istanza
+ ed in particolare è un'instanza della classe /ClassName/
+- /field/ per creare relazioni tra i vari campi di una classe e l'istanza
+
+Se dovessero verificarsi degli errori durante la creazione dell'istanza
+le informazioni residue vengono rimosse tramite /retract/ prima
+di restituire un fallimento.
+
+**** Ricerca di un'istanza
+Data una *variabile* come nome d'istanza, un atomo rappresentante una
+classe *necessariamente* definita in precedenza ed un'opzionale lista
+di "assegnamenti" a field della classe, cerca all'interno della
+base di conoscenza un'istanza precedentemente definita.
+
+Questo predicato sfrutta il potente meccanismo di back-tracking di
+Prolog per cercare di unificare la variabile /InstanceName/ con
+un'istanza della classe /ClassName/ che, se la lista di "assegnamenti"
+non è nulla, abbia i valori dei field specificati.
+/Naturalmente se non si ha nessun "assegmaneto" allora InstanceName/
+/unifica con tutte e sole le istanze della classe specificata./
*** Implementazione
#+begin_src prolog :tangle oop.pl
** field
*** Definizione
-Assegna dinamicamente ed estrae il valore di un field di un'istanza.
-
+Assegna tramite /assert*/ e recupera il valore di un field data un'istanza.
Questa funzione svolge lo stesso compito di un getter/setter in
-un *inferiore* linguaggio ad oggetti, ovvero una funzione che fornisce
-un modo controllato per accedere al valore di un attributo all'interno di
-un'istanza.
+un *inferiore* linguaggio ad oggetti sfruttando il meccanismo di
+back-tracking.
*** Implementazione
#+begin_src prolog :tangle oop.pl
** fieldx
*** Definizione
-Estrae il valore dalla classe percorrendo una catena di attributi.
-Il caso base del metodo è quando /FieldName/ è una lista formata da
-un solo elemento, con il predicato /field/ possiamo estrattre l'ultimo
-(e solo) valore di /FieldName./
-Se /FieldName/ ha più elementi possiamo richiamare il metodo ricorsivamente
-sulla coda della lista finchè la lista non avrà un solo elemento
-riportandoci al caso base.
+Data un'istanza, sia essa una variabile o un atomo, ed una lista
+non vuota di field, estrae il valore associato all'ultimo elemento
+della lista di field dell'ultima istanza.
+
+Questo predicato e la seguente clausola sono equivalenti.
+#+begin_src prolog
+field(instance, field1, Valore1),
+field(Valore1, field2, Valore2),
+field(Valore2, field3, Risultato),
+fieldx(instance, [field1, field2, field3], Risultato). %% true.
+#+end_src
*** Implementazione
#+begin_src prolog :tangle oop.pl
** inst
*** Definizione
-Dato un oggetto che rappresenta un'istanza restituisce il nome
-dell'istanza.
-Si nella nostra implementazione è banale perchè l'oggetto che rappresenta
-l'istanza è il nome dell'istanza.
+Dato il nome con cui è stata create l'istanza restituisce l'istanza
+stessa.
+
+Dato che nella nostra implementazione la creazione di un'istanza è la
+semplice aggiunta alla base di conoscenza del fatto
+/is_instance(InstanceName)/ questo predicato si limita a controllare
+che il nome dato in ingresso è un'istanza.
*** Implementazione
#+begin_src prolog :tangle oop.pl
-inst(InstanceName, InstanceName).
+inst(InstanceName, InstanceName) :-
+ is_instance(InstanceName).
#+end_src
*** Esempio pratico
* Predicati helper
** Predicati dinamici
-Predicati usati dal metodo /asserta/, svolgono una funzione di controllo
-per diverse entità.
+Predicati utilizzati da /assert*/ all'interno delle altre funzioni
+per tenere traccia di cosa rappresentano i simboli definiti.
#+begin_src prolog :tangle oop.pl
:- dynamic is_class/1.
#+end_src
** Aggiunta di `field` e `metodi`
-Data una classe devo poter dire che un `field` appartiene alla classe
-che sto definendo.
-Se non ci sono `field`/`metodi` da bindare allora è finita la definizione
-delle parti della classe.
+Le seguenti regole servono per creare relazioni tra una classe ed i suoi
+*membri* ovvero /field/ e /methods/.
+Di base, il successo di questo predicato dipende dal fatto che il simbolo
+dato in ingresso *deve* essere una classe precedentemente definita.
+In caso contrario non sarebbe possibile creare una relazione con i membri.
#+begin_src prolog :tangle oop.pl
add_part(ClassName, []) :- is_class(ClassName), !.
#+end_src
-Se viene dato un `field` privo di tipo controlliamo che non sia già presente
-nella base di conoscenza e se lo è lo cancelliamo sennò facciamo il
-binding di classe e field dicendo che il tipo è `nil` e quindi
-dinamico(stile *python*).
-
+Dato un field da aggiungere alla classe è necessario controllare che
+quest'ultimo non sia già in relazione con la classe, questo vorrebbe
+dire che il campo è già stato ereditato ed è quindi necessario effettuare
+l'override con il nuovo valore.
#+begin_src prolog :tangle oop.pl
add_part(ClassName, [field(Name, Value) | OtherParts]) :-
is_class(ClassName),
add_part(ClassName, OtherParts).
#+end_src
-Se invece viene dato un `field` come prima controlliamo se è già definito
-ma inoltre controlliamo che il `value` sia dello stesso tipo di `type`.
-
+Similarmente al caso precedente se il field da aggiungere è anche
+dotato di un /type/ allora viene effettuato il controllo del tipo
+del valore prima di modificare la base di conoscenza.
#+begin_src prolog :tangle oop.pl
add_part(ClassName, [field(Name, Value, Type) | OtherParts]) :-
is_class(ClassName),
add_part(ClassName, OtherParts).
#+end_src
-Se viene dato un `method` allora definiamo nella base di conoscenza un
-predicato `Name(InstanceName, ArgList)`.
-
+Il caso dell'aggiunta di un metodo è particolare, in quanto possiamo
+ignorare il fatto che il metodo potrebbe essere già stato definito
+da un genitore.
+Questo è possibile aggiungendo l'operatore /cut/ al corpo del "metodo"
+impedendo quindi al back-tracking di esplorare le definizioni alternative
+dello stesso "metodo".
+
+L'/installazione/ del metodo viene fatta aggiungendo alla
+base di conoscenza la funzione /Name(InstanceName, Args)/ ottenuta
+dall'operatore prolog "=.." che ricrea il termine composto /Head/ dalla lista
+contenente le informazioni del metodo dato in ingresso.
+
+Inoltre dato che all'interno del corpo deve essere possibile utilizzare
+l'atomo /this/ per fare riferimento all'instanza stessa viene effettuata
+un'operazione di sostituzione di quest'ultimo con una variabile che
+unificherà con il nome dell'istanza su cui dobbiamo chiamare il "metodo".
#+begin_src prolog :tangle oop.pl
add_part(ClassName, [method(Name, ArgList, Body) | OtherParts]) :-
is_list(ArgList),
#+end_src
** Impostazione dei field ereditati
-Mi dai una lista di `field` presi da una superclass e fai il binding anche
-con questa classe.
+Predicato usato durante la creazione di un'istanza.
+Data l'istanza ed i field della classe genitore, controlla che essi siano
+del tipo corretto e modifica la base di conoscenza aggiungendo una
+relazione tra ogni field e il simbolo che rappresenta l'istanza.
#+begin_src prolog :tangle oop.pl
set_superclass_fields(_InstanceName, _ClassName, []) :- !.
#+end_src
** Costruzione di un'istanza
-Fai il binding tra i `field` di un classe e quelli di un'istanza come
-`add_part`.
+Predicato equivalente ad /add_part/ per l'impostazione dei field
+di un'istanza.
#+begin_src prolog :tangle oop.pl
set_fields(_InstanceName, _ClassName, []) :- !.
** Sostituzione del termine `this`
Predicato utilizzato per sostituire l'atomo /this/ con la vera istanza.
Dato un predicato /Body/ questo viene separato nei suoi termini costituenti
-e (/funtore e argomenti/) *per ogni* argomento richiama la /replace/.
+(/funtore e argomenti/) e *per ogni* argomento richiama la /replace/.
In questo modo possiamo cercare l'atomo da sostituire anche all'interno di
termini composti come chimate di funzioni.
** Definizione di una classe
*** Effettivo predicato `def_class`
-La definizione di una classe richiede che `classname` non sia già il nome
-di una classe pre-esistente nella base di conoscenza.
-Una volta effettuato questo controllo possiamo ereditare tutti
-i field ed i metodi dalle classi genitore se presenti e creare relazioni
-tra le /parts/ della classe da creare ed il nome della classe stessa grazie
-al predicato /add_part/.
+Predicato utilizzato per la definizione della classe ricevuta da
+[[*def_class][def_class]].
+Dato che questa funzione utilizza /assert*/ per modificare la
+base di conoscenza, se dovessore verificarsi degli errori queste
+modifica rimarrebbero presenti.
+Per ciò non è consigliato utilizzare /def_class/ al suo posto.
+
+Prima di aggiungere le informazioni della nuova classe alla base
+di conoscenza vengono ereditate tutte le parti (/field e metodi/)
+dalla lista di genitori.
+Questo viene fatto per permettere ad una classe di estendere il
+comportamento dei metodi o di cambiare valore/tipo dei parametri
+definiti dalle classi genitore.
#+begin_src prolog :tangle oop.pl
wrapped_def_class(ClassName, Parents, Parts) :-
nonvar(Parents),
nonvar(Parts),
\+ is_class(ClassName),
+ atom(ClassName),
set_superclass(ClassName, Parents),
asserta(is_class(ClassName)),
Dopo di chè creiamo una relazione tra il genitore e la classe figlio
che creerà una gerarchia di classi utile nel [[*Controllo dei tipi][controllo dei tipi]].
+Questo permette ad un'istanza della classe figlio di
+accedere *direttamente* ad ogni campo/metodo definito da una
+classe genitore.
#+begin_src prolog :tangle oop.pl
set_superclass(_ClassName, []) :- !.