-#+title: 🔥 OOΛ in Common Lisp 🔥
+#+title: OOΛ in Common Lisp
#+author: Bizzoni Leonardo (899629)
#+author: Kier Mirko Tolentino(899728)
(format "Sum: ~D~%" (+ number (field this 'foo))))))
(def-class 'bar nil
- '(fields (bar "42"))
+ '(fields
+ (bar "42" string)
+ (baz nil foo))
'(methods
(foo ()
(format "Favourite number is ~D~%" field(this 'bar)))))
*** Esempio pratico
#+begin_src lisp
(defparameter f (make 'foo))
-(defparameter b (make 'bar 'bar "42"))
+(defparameter b (make 'bar 'bar "Ciao mondo!" 'baz f))
#+end_src
** field
*** Esempio pratico
#+begin_src lisp
-(field* foobar 'a 'b 'c)
+(field* b 'baz 'foo) ;; 42
#+end_src
#+end_src
** Creazione di un'istanza
+La creazione di un'istanza data la rappresentazione in forma di lista di
+una classe è una banale modifica al valore della keyword /:type/ in /'object/.
+Durante la creazione di un'istanza è anche possibile passare una sequenza
+di /'fieldname new-value/ per modificare il valore di default di uno più
+field.
+Naturalmente se si cerca di "assegnare" un valore ad un field *non* presente
+nella definizione della classe questo provocherà un errore.
#+begin_src lisp :tangle ool.lisp
(defun create-instance (listclass new-fields)
(first new-fields) ;; nome del field
(second new-fields)) ;; nuovo valore
(cdr (cdr new-fields)))))
-#+end_src
-
-*** Impostare i campi dell'istanza
-
-#+begin_src lisp :tangle ool.lisp
(defun set-instance-field (instance name value)
- ;; `setf` modifica in-place
(setf (getf instance :fields)
(set-field (getf instance :fields) name value))
- ;; quindi serve resistuire `instance`
instance)
(defun set-field (fields name value)
#+end_src
** Stabilire se un simbolo è una classe
+Per stabilire se il simbolo /name/ dato rappresenta una classe basta
+cercare all'interno dell'hash-table il nome e, se presente, verificare
+che il valore della keyword /:type/ all'interno della rappresentazione in
+forma di lista della classe sia il simbolo /'class/.
+/Vedi [[*Creazione della classe in formato lista][creazione di una classe]] per maggiori informazioni sulla
+struttura di una classe./
#+begin_src lisp :tangle ool.lisp
(defun is-class (name)
nil))
#+end_src
-** Controlla se il simbolo passato è un'instance della classe
+** Stabilire se un simbolo è un'istanza
+Il conportamente di questo predicato varia in base agli argomenti
+che gli vengono dati.
+
+Se viene dato solo un argomento allora il predicato deve stabilire se
+l'argomento /instance/ è un'istanza di una generica classe.
+Per essere un'istanza, /instance/ deve essere una lista ed avere
+/'object/ come valore della keyword /:type/.
+Se invece viene dato anche un nome rappresentante una classe, allora
+il predicato deve verificare che /instance/ non sia solo una generica istanza
+ma anche un'istanza della classe /class-name/ o un'istanza di una sua
+classe figlia.
#+begin_src lisp :tangle ool.lisp
(defun is-instance (instance &optional (class-name t))
(and (listp instance)
(eq (getf instance :type) 'object)))
- (and (listp instance)
- (or (eq (getf instance :classname) class-name)
- (member class-name (getf instance :parents)))
- (eq (getf instance :type) 'object))))
+ (or
+ (null instance)
+ (and (listp instance)
+ (or (eq (getf instance :classname) class-name)
+ (member class-name (getf instance :parents)))
+ (eq (getf instance :type) 'object)))))
#+end_src
+Inoltre, per semplificare l'utilizzo di una classe come tipo di un /field/,
+si assume che /nil/ sia un'istanza di qualunque classe.
+
** Controllo tipo valore
+Il controllo dei tipi si divide un 2 parti:
+- controllo di un valore dato un field
+- controllo di un valore dato un tipo
+Il primo caso viene utilizzato principalmente durante la creazione di
+un'istanza per verificare, se presenti degli "assegnamenti", che i valori
+siano del tipo indicato dal field della classe.
+
+#+begin_src lisp :tangle ool.lisp
+(defun type-check-field (field value)
+ (if (eq (length field) 2)
+ t
+ (type-check value (third field))))
+#+end_src
+
+Il secondo caso viene utilizzato principalmente durante la creazione di
+una classe principalmente per controllare che tutti i field definiti siano
+del tipo corretto.
+In particolare, dato che un field può essere sia una tupla /(name value)/ che
+una tripla /(name value type)/, nel caso in cui /field/ non sia dotato di un
+tipo non si ha la necessità di effettuare alcun controllo
+su di esso, il /field/ avrà quindi un tipo /dinamico/.
+Viceversa se il /field/ è dotato di tipo, esso potrà essere:
+- un tipo implementato da lisp, dove il controllo del tipo del valore
+ viene svolta dalla funzione nativa /typep/
+- una classe, dove il valore deve essere un'istanza della classe stessa
#+begin_src lisp :tangle ool.lisp
(defun validate-fields-type (fields)
"o è una terna (name value type)"
"o una coppia (name value)"))))
-(defun type-check-field (field value)
- (if (eq (length field) 2)
- t
- (type-check value (third field))))
-
(defun type-check (value type)
(if (is-class type)
(if (is-instance value type)
(cdr (cdr new-fields)))))
(defun set-instance-field (instance name value)
- ;; `setf` modifica in-place
(setf (getf instance :fields)
(set-field (getf instance :fields) name value))
- ;; quindi serve resistuire `instance`
instance)
(defun set-field (fields name value)
(and (listp instance)
(eq (getf instance :type) 'object)))
- (and (listp instance)
- (or (eq (getf instance :classname) class-name)
- (member class-name (getf instance :parents)))
- (eq (getf instance :type) 'object))))
+ (or
+ (null instance)
+ (and (listp instance)
+ (or (eq (getf instance :classname) class-name)
+ (member class-name (getf instance :parents)))
+ (eq (getf instance :type) 'object)))))
+
+(defun type-check-field (field value)
+ (if (eq (length field) 2)
+ t
+ (type-check value (third field))))
(defun validate-fields-type (fields)
(cond ((null fields) nil)
"o è una terna (name value type)"
"o una coppia (name value)"))))
-(defun type-check-field (field value)
- (if (eq (length field) 2)
- t
- (type-check value (third field))))
-
(defun type-check (value type)
(if (is-class type)
(if (is-instance value type)