= Variante 2: Operazioni estendibili = === Note preliminari sul documento === Questo documento intende essere punto di riferimento in fase di sviluppo e germe della documentazione che accompagnera' il progetto. Questo documento e' presente in duplice copia: fra i sorgenti in modo da essere facilmente editabile e leggibile in fase di sviluppo, e sul [wiki:Variante2 wiki] e fra i [source:branches/var2/doc/Appunti sorgenti] per aumentarne la facilita' di utilizzo. Dal momento che i commenti sul wiki possono essere lasciati anche da chi non segue direttamente lo sviluppo, l'utilizzo del file presente nei sorgenti e' da ritenersi una copia della pagina wiki; pertanto chi effettua modifiche al primo si dovra` preoccupare di sincronizzarlo tempestivamente con il secondo. In caso di divergenze di opinioni su una sezione e' preferibile il commento pittosto della brutale modifica, in modo da tenere traccia delle considerazioni fatte. Convenzioni utili per i commenti: * posporli alla sezione a cui fanno riferimento; * usare il carattere ''corsivo'' per indivduarli facilmente; * premettere il nome dell'autore accompagnato dalla data. == Specifiche == Si assuma che il numero e la struttura dei costrutti del linguaggio !MiniScheme sia dato e non soggetto a cambiamenti: * Si fornisca l'implementazione di tutti i costrutti originali Si assuma che il numero delle operazioni polimorfe sia destinato ad evolvere rapidamente * Si fornisca un interprete e una prettyPrint modulari Il modello deve supportare la definizione modulare di operazioni. * Si vuole supportare la definizione di operazioni modulari sia sotto forma di visitors che di iteratori * Il modello deve fornire API di manipolazione specifiche e generiche * L'aggiunta di una operazione non deve richiedere nessun cambiamento al modello [[BR]]20060819-1310 [SoujaK] ''Le operazioni non devono perrtanto risiedere all'interno del modello, ma all'esterno, negli specifici visitor/iterator. Il modello esporra' nella sua interfaccia la classica `accept(AbstractVisitor)`. Raggruppare l'interfaccia dei visitor permette al modello di essere totalmente indipendente dall'aggiunta di nuove operazioni.'' [[BR]] 20060819-1617 [SoujaK] [[BR]] ''E per quanto riguarda gli iteratori?'' Le scelte di design devono essere imposte al cliente. * Si vuole imporre al cliente l'uso dei pattern stabiliti (in particolare quelli creazionali) * Il codice e i pattern non conformi a questa specifica non devono fare parte del sistema fornito [[BR]] 20060818-1501 [SoujaK] ''Quali pattern creazionali? E' necessario il redesign di questa sezione, oppure la vecchia Factory adempie gia' a questo compito? Volendo si potrebbe pensare a soluzioni alternative, ma reputo la cosa a bassa priorita'.'' == Diaro di bordo: dubbi, problemi e conseguenti scelte == === Il modello === 200606??-???? [[BR]] `Branch`: diventeranno figlie delle `Expression`? 20060820-1238 [SoujaK] [[BR]] Natura del modello: la struttura solitamente pensata come un albero di espressioni e' rappresentata grazie a campi interni degli oggetti che compongono l'aggregato. Si tratta di `List` o `ArrayList` nel caso di nodi non terminali, altrimenti tipi specifici (bool, String, int) a seconda del caso. Il problema che sorge e' come riuscire a far attraversare un aggregato cosi' eterogeneo da un Iterator. [[BR]] Forse potrebbe avere senso fare come e' stato fatto per Variante 1, cioe' far diventare i campi interni degli `SchemeValue`. Si tenga pero' presente che lo SchemeValue e', di per se', gia' un prodotto della valutazione === API di manipolazione generica === 20060725-1758 [gnappo] [[BR]] Le API di manipolazione generiche sono dei getter e setter che agiscono sull'intero modello. Per approfondire seguite il [http://www.cs.unibo.it/~solmi/teaching/labss_2005-2006/EserciziProgetto2.pdf link]. Se non bastasse vi rimando all' [http://www.cs.unibo.it/~solmi/teaching/labss_2005-2006/esercizi/labss_il_model_iterators.zip esempio] del prof. Solmi: prestate attenzione alle classi !LanguageEntity e alle varie Abstract* (sono particolarmente chiarificatrici). 20060818-1918 [SoujaK] [[BR]] Le API di manipolazione generica sul modello possono essere implementate in un genitore comune che fornira' l'operazione di default (verosimilmente il sollevamento di un eccezione). 20060923-1120 [Roma] [[BR]] Grazie alle API di manipolazione generica possiamo gestire in tutto per tutto quelle che Solmi chiama [LanguageEntity].Dando un'occhiata alla suddetta classe si può notare come questa associ un indice sia all'entità padre sia ai suoi figli. La funzione getType() inoltre restituisce il tipo di entità;ancora però non riesco a capire bene a cosa ci possa servire il sapere di che tipo è un'entità. Gli indici servono per navigare il sottoalbero di espressioni quindi in ogni istante posso sempre sapere a che livello dell'albero mi trovo (dare un'occhiata alla classe [EntityIterator]). === API di manipolazione specifica === 20060820-1332 [SoujaK] [[BR]] Le API di manipolazione specifica (`getter` e/o `setter`) diventano piu' che mai necessari in questa variante, perche' le operazioni sul modello devono essere effettuate all'esterno di esso. Affinche' i `Visitor` riescano nel loro intento hanno ovviamente bisogno di conoscere l'oggetto che intendono visitare. === Visitor === 20060820-1817 [SoujaK] [[BR]] Durante l'implementazione dei Visitor si pone un problema di natura progettuale: chi e` responsabile dell'attraversamento della struttura a oggetti?[[BR]] La possibilita' di utilizzare un Iterator esterno e` stata discussa da tutta la squadra e non verra' realizzata sebbene si lasci tale facolta' al cliente. Rimane pertanto da chiedersi se chi si fa carico dell'iterazione e' la stessa struttura ad oggetti (come accade sovente a detta della GoF) oppure i `Visitor` (si veda "GoF - ''Design Pattern'' - pagg 340-1). [[BR]] Il dott. Solmi, nel suo esempio sui `Visitor` snatura il significato di `Visitor` declassandoli a miseri `proxy` usati per evitare di esporre pubblicamente le operazioni come `evaluate` o `prettyPrint`. La richiesta di chiarimenti, inoltrata al professore esattamente un mese fa (20060720-1854), non ha ancora avuto risposte.[[BR]] A mio avviso demandare l'attraversamento della struttura a oggetti `Visitor` e' la soluzione migliore in termini di eleganza e chiarezza dell'algoritmo di visita, dal momento che la sua implementazione risiede, in tutte le sue componenti, proprio fra i metodi di visita degli oggetti. [[BR]] 20060821-1316 [SoujaK] [[BR]] Nell'implementazione dell'interfaccia del `Visitor` ho preferito usare nomi diversi per i vari metodi (`visitA()`, `visitB()` ...), piuttosto che un unico metodo `visit()` sovraccaricato. La chiarezza del codice aumenta. [[BR]] 20060827-1326 [SoujaK] [[BR]] Cosi' facendo ci si gioca la possibilita' di trattare genericamente con delle Expression. Nell'implementazione delle operazioni polimorfe questa diventa quasi una necessita' poiche' costringerebbe a controllare la classe di appartenenza dell'oggetto che vogliamo visitare: si parla di if-else in cascata. Per venire a capo della cosa il dott. Solmi aggiunge ai suoi costrutti un metodo ''ad-hoc'' che permette di identificare il costrutto, mettendolo in corrispondenza con una enumerazione. 20060826-2018 [SoujaK] [[BR]] Sto iniziando l'implementazione del `VisitorInterpreter`: non devono forse riuscire ad attraversare qualsiasi componente del modello, compresi gli stessi Value e le Definition, dal momento che si riferisce alle operazioni sul modello come '''polimorfe'''? 20060827-1744 [SoujaK] [[BR]] Come si gestisce il passaggio delle informazioni indispensabili al processo di valutazione, in relazione al pattern `Visitor`? Il modo piu' immediato e' inserire, dove necessario, un Environment fra i parametri di ingresso e un Value fra quelli di uscita nei metodi accept() e visit(). Cosi' si diminuisce l'omogeneita' delle varie Expression e si sporca l'interfaccia classica di questo pattern. 20060827-1905 [SoujaK] [[BR]] La soluzione per cui ho optato e' quella di utilizare campi interni al visitor. Aggiungere ai `Visitor` uno stato interno e' una pratica piuttosto diffusa che non intacca l'eleganza del pattern, pur aumentandone le potenzialita': * nel caso della prettyPrint potrebbe essere lo stato potrebbe essere sfruttato come contatore dei livelli di indentazione; * l'`Interpreter` invece potrebbe mantenere internamente un `Value` e un `Environment`. 20060828-1328 [SoujaK] [[BR]] Ecco come ho pensato debbano andare le cose per la visita dell'`Interpreter`: {{{ // prima: value = expression.evaluate(environment); // ora: interpreter.setEnv(environment); expression.accept(interpreter); value = interpreter.getResult; }}} Non ho ancora approfondito come le successive invocazioni di `accept()` si comportino durante la ricorsione, e se i due campi interni rimangano coerenti; tantomeno ho avuto modo di testare praticamente il codice prodotto. [[BR]] La mancanza di eleganza che i lettori piu' sofisticati hanno sicuramente notato potra' in futuro venire nascosta da un metodo proxy di questo genere: {{{ SchemeValue interpret(SchemeExpression expr, SchemeEnvironment env) }}} === Varie === 200606??-???? [[BR]] Gli iterator sono da intendersi come esterni. == Operazioni aggiunte: `contrib` == Questo e' il posto in cui rendere note le proprie scelte.