Newsgroup: it.comp.lang.c++
Titolo: principio di sostituibilita'

ciao a tutti,
e' vero che il principio in soggetto dice che
una classe derivata deve poter essere sostituita
alla relativa classe base senza che il compilatore
si arrabbi?
Potete farmi un esempio in cui cio' non e' rispettato?
grazie
--
Tiberio Grasso

Potete farmi un esempio in cui cio' non e' rispettato?
Solita classe Shape, con le ovvie derivate Square, Circle
Una funzione del genere non rispetta il principio di sostituibilita' (di
Liskov)
(poiche' usa la RTTI anziche' il polimorfismo, ma lasciamo stare!!!):
void DrawShape(const Shape& s)
{
   if (typeid(s) == typeid(Square))
      DrawSquare(static_cast<Square&>(s));
   if (typeid(s) == typeid(Circle))
      DrawCircle(static_cast<Circle&>(s));
}
Domani implementi la classe Triangle e la funzione DrawShape non funziona
(nel senso che non fa quello che ti aspetteresti...)
Ciao,
Gianfranco
P.S. c'e' un interessante articolo di Robert Martin,
intitolato guarda caso "The Liskov Substitution Principle",
pubblicato su C++ Report nel 1996 e *liberamente* scaricabile dal suo
sito (assieme ad altri articoli sull'OOD) 
www.objectmentor.com

 sito (assieme ad altri articoli sull'OOD) 
www.objectmentor.com
Ci faccio senz'altro un salto. Grazie.
EMG


Il Principio si sostituibilita` di Liskov (Barbara Liskov) cerca di
definire il significato della derivazione (il famoso B is-a A),
ovvero il concetto di sottotipo e supertipo.
In pratica non e` sufficiente che  B derivi (sintatticamente) da A
affinche` B sia sottotipo di A. La definizione di sottotipo e`
*comportamentale* e non strutturale, non basta che B abbia la stessa
interfaccia di A.
B e` un sottotipo di A se e solo se per ogni programma
che usa istanze di A posso usare in alternativa istanze di B
senza che il comportamento logico del programma cambi,
ovvero se P e` una proprieta` verificata dalle (tutte) istanze di
A allora P deve essere vera anche per le istanze di B.
C'e` un buon articolo di Pescio in merito su
Computer Programming N.71 (luglio/agosto '98)
Paolo
-----------------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
-----------------------------------------------------------------

intitolato guarda caso "The Liskov Substitution Principle",
Grazie, andro` subito a leggerlo.


Perfetto!


Bravo Paolo!
Non ci ho riflettuto abbastanza a lungo...
Ciao,
Gianfranco

 definire il significato della derivazione (il famoso B is-a A),
[snip]
Da qualche parte si comincia a dire che non e' tanto "IS-A", ma
"BEHAVE-AS-A".
La distinzione nasce dal fatto che prima relazione puo' indurre in errori di
valutazione (esempio, lo struzzo "IS-A" uccello, ma non "BEHAVE-AS-A"
uccello dato che non vola).
MM

 Grazie, andro` subito a leggerlo.
Ma non c'è un formato più comodo da leggere del PDF? O qualche utility
per convertire un PDF in semplice testo?
EMG

grazie!
Tiberio

Non ci ho riflettuto abbastanza a lungo...
Beh, d'altronde non e` proprio banale da capire e neppure le conseguenze
(anzi... quelle sono ancora piu` difficili)!


uccello dato che non vola).
Interessante distinzione, bisogna pero` considerare che gli oggetti 
della oop molto difficilmente sono gli stessi oggetti della realta`.
Nel tuo esempio direi che l'errore e` nell'implicita assunzione che
un "uccello" vola, mentre non e` vero che tutti gli uccelli volano.
IMO si tratta di una errore di analisi. Non sei d'accordo?


Enrico Maria Giordano wrote:

Scusa ma perche' il PDF sarebbe scomodo ?
Acrobat Reader esiste (free) anche per windows. Non conosco l'indirizzo
esatto dove poterlo scaricare
ma una piccola ricerca in rete  dovrebbe essere sufficiente.
Marco Guidi


Devo dire che non ho fatto un'analisi esaustiva del problema :-) dato che lo
presentavo solo come esempio. In effetti non tutti gli uccelli volano,
quindi la classificazione dovrebbe essere piu' complessa di quella da me
indicata (d'altronde era solo un esempio).
Non concordo con la tua prima affermazione. Io direi che spesso gli oggetti
delle oop corrispondono agli oggetti della realta'...nota spesso, non
sempre. Certo, molti oggetti che si introducono durante la fase di design
non hanno corrispondenza nel modo reale, ma ribadisco, non direi 'molto
difficilmente'.
Resta comunque il fatto che se un oggetto e' comportamento (certamente non
e' dati ;-)) la definizione behave-has-a e' molto piu' indicata della is-a
per capire come gestire un determinato tipo di relazioni.
MM

 uccello dato che non vola).
Per coloro cui interessa, una discussione approfondita e' nelle FAQ di
comp.lang.c++; "[21.6] Is a Circle a kind-of an Ellipse?" e seguenti:
[21.7], [21.8], [21.9].
-- 
Maurizio Loreti                      
http://wwwcdf.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it


A questo punto si potrebbe aprire un'interessante discussione circa il
significato dell'ereditarieta'.
*Attualmente* (diciamo che mi sto facendo le ossa in fatto di
design/programmazione *realmente* OO) sono sostanzialmente d'accordo con
Massimo: l'ereditarieta' pubblica dovrebbe sott'intendere che le classi
derivate presentano (a chi ne fa un uso esterno, in sostanza al client della
classe) un funzionamento simile a quello della classe base. Nell'esempio di
Massimo, se la classe Uccello esporta il metodo Vola, necessariamente
Struzzo non puo' discendere da Uccello (un bel "return FALSE" potrebbe
essere la panacea?). La discendenza di Struzzo da Uccello dipende dunque
dall'interfaccia di Uccello, quindi dal modello che si va definendo. Forse
il problema nasce dal fatto che naturalmente nella nostra mente lo Struzzo
e' un Uccello perche' questa e' la gerarchia che abbiamo studiato in
biologia alle scuole medie, e da allora non abbiamo mai avuto la necessita'
di cambiarla; perche' fare la fatica prendere carta e penna e reinventare
una nuova gerarchia, quando tutto sommato si puo' avviare l'editor e
digitare "class Struzzo : public Uccello" con una certa tranquillita'? A
pensarci bene, l'osservazione di Massimo ci obbliga a mettere in discussione
tutti gli schemi mentali che a fatica ci siamo costruiti fin'ora...
Saluti,
Gianfranco

 ma una piccola ricerca in rete  dovrebbe essere sufficiente.
Si, lo so. L'ho scaricato è l'ho trovato estremamente scomodo. Per
leggere devi per forza ingrandire la pagina e spostarti all'interno di
essa. E poi non ho trovato il modo di cambiare lo sfondo bianco
brillante della pagina che mi fa venire il mal di testa dopo dieci
secondi. Se trovassi un convertitore PDF -> TXT sarebbe il massimo...
EMG



A proposito dell' articolo di Pescio.

Sono tutti in rete sul sito della eptacom

www.eptacom.net


p.s.: io non ci guadagno niente !  :-)

 

 

 

Il Principio si sostituibilita` di Liskov (Barbara Liskov) cerca di

definire il significato della derivazione (il famoso B is-a A),

ovvero il concetto di sottotipo e supertipo.

In pratica non e` sufficiente che  B derivi (sintatticamente)
da A

affinche` B sia sottotipo di A. La definizione di sottotipo e`

*comportamentale* e non strutturale, non basta che B abbia la stessa

interfaccia di A.

B e` un sottotipo di A se e solo se per ogni programma

che usa istanze di A posso usare in alternativa istanze di B

senza che il comportamento logico del programma cambi,

ovvero se P e` una proprieta` verificata dalle (tutte) istanze di

A allora P deve essere vera anche per le istanze di B.

C'e` un buon articolo di Pescio in merito su

Computer Programming N.71 (luglio/agosto '98)

Paolo

-----------------------------------------------------------------

  Paolo Marotta

  Computer Science, University of Pisa

  home:   
http://www.cli.di.unipi.it/~marotta


-----------------------------------------------------------------


-- 

Giovanni La Rocca

ghia...@iol.it

 


 per convertire un PDF in semplice testo?
Si, si tratta di ghostview.
Lo trovi su 
http://www.cs.wisc.edu/~ghost/
Io l'ho scaricato ed è ottimo. (si pianta qualche volta)
A me serviva per i file .ps, ma ho visto che legge anche i .pdf
Questa dritta me l'aveva data qualcun altro tramite news, ma non ricordo
chi.
--
Alessandro Monti


www.eptacom.net
Non ci avevo pensato...


[21.7], [21.8], [21.9].
So che e` grave, ma dove le trovo?
Paolo


per capire come gestire un determinato tipo di relazioni.
Un oggetto non e` *solo* comportamento...
Per quanto riguarda il behave-as-a, molto spesso l'errore e` quello di 
utilizzare l'ereditarieta` pubblica quando notiamo similitudini che
rendono Derived simile a (behave-as-a) Base, ma non sostituibile.
Quello che in quei casi si vuole fare e` in
realta`  sfruttare l'implementazione di Base, in questi casi 
bisognerebbe derivare privatamente. L'eredita` privata non modella
infatti una relazione is-a poiche` nasconde l'interfaccia ereditata, ma
consente ancora di riutilizzare il comportamento (e non solo) di Base.
Questo caso mi e` capitato una volta nella realizzazione della classica
gerarchia shape. In una occasione l'ereditarieta` multipla mi ha
permesso di ottenere una classe D tale che D Is-a B e D "behave-as-a" C.
La differenza tra D e B era unicamente nel costruttore: se non ricordo
male B era un poligono, mentre D era un cerchio e C un arco.
I punti di un cerchio erano ottenibile costruendo un arco di 360 gradi e
"chiudendo" la linea, la derivazione privata da C mi ha permesso di
riciclare il costruttore di C evitando che un cerchio fosse usato in
luogo di un arco.
La nostra discussione non e` comunque un caso, come non e` un caso
che alcuni modelli di OOP non offrono l'ereditarieta`, si tratta di un
meccanismo apparentemente semplice da usare, ma che in realta`
nasconde molte insidie visibili solo a medio-lungo termine.
Probabilmente una relazione behave-as-a si presta bene ad essere
modellata con la delegation, ma la delagation la conosco poco e
potrei sbagliarmi.


So che e` grave, ma dove le trovo?
E' terribile: come puoi avere avuto una infanzia felice senza
sapere dove erano le faq?  :)
http://www.cerfnet.com/~mpcline/c++-faq-lite


Per completare la discussione, puo' essere utile vedere cosa dice Bertrand
Meyer.
All' indirizzo
http://www.eiffel.com/doc/manuals/technology/oosc/inheritance-design/
c' e' un capitolo del suo libro che tratta della derivazione.
L' ho trovato in questi giorni, e lo sto giusto leggendo.
Ciao!

sapere dove erano le faq?  :)
La mia infanzia risale ai tempi del commodore vic20 e del
basic...
All'epoca il principio di sostituibilita` non era stato neppure 
formulato!!!!
Paolo
P.s.
  Grazie per il link!


 So che e` grave, ma dove le trovo?
Il sito madre e' 
http://www.cerfnet.com/~mpcline/c++-faq-lite/
 ; ci
sono molti mirrors.  Vale la pena di comperare l'edizione stampata
(Addison-Wesley) --- o di farla comperare dalla biblioteca --- adesso
che il linguaggio e' standardizzato e non ci sono piu' stati grossi
cambiamenti.


 consente ancora di riutilizzare il comportamento (e non solo) di Base.
In questi casi preferisco utilizzare il contenimento (o aggregazione) dato
che considero assente il concetto di specializzazione (anche se riconosco il
significato della ereditarieta' d'implementazione.
Nel caso dello struzzo, esso non 'behave-as-a' uccello dato che non puo'
volare (a meno che non prenda l'aereo). Alcuni, sfruttandone l'appartenenza
alla specie degli uccelli (peraltro un po' troppo generica per poterne fare
una classe base), potrebbero dire che lo struzzo 'is-a' uccello e cosi
cadrebbero nell'errore di dover magari rendere NOP il metodo Vola().
MM

 essere la panacea?). ...
No, non e' il caso.
La classe cliente di Uccello si aspetta che qualsiasi specializzazione dello
stesso possa volare. Ritornare FALSE sarebbe un effettos econdario non
corretto del metodo Vola(). Piuttosto dovresti utilizzare una query
SaiVolare() che ti ritorna la capacita' dell'uccello di volare o meno.
Personalmente non amo questa seconda soluzione perche' comporterebbe che in
un ciclo che, ad esempio, prevede di far volare tutti gli uccelli di un
allevamento dovrei per ognuno di essi eseguire l'if...
No, non metterei l'if internamente al metodo vola perche il cliente si
aspetta che l'uccello voli (in un modo o nell'altro) quindi non mi piace
l'idea di dire ad un uccello di volare e ritrovarmi con quest'ultimo, sempre
fermo a terra, che mi guarda con compatimento.
Quando ti capita di avere una classe derivata che deve 'eliminare'
funzionalita' richieste dalla classe base la soluzione e' di rivedere il
disegno della gerarchia di classi.
La classe base dovrebbe avere *solo* i metodi comuni alla specie. Quindi nel
nostro caso la classe Uccello non dovrebbe avere il metodo Vola(). Si deriva
da Uccello due classi che lo specializzano, es. UccelloCheVola e
UccelloCheNonVola, e da queste due derivare le successive specializzaizoni.
Oppure, si potrebbe dotare la classe Uccello di un attributo _couldFly, che
indica la capacita' o meno di volare.
Resta il fatto che se in Uccello e' presente il metodo Vola() ogni classe
che deriva da essa deve eseguire tale metodo...quindi ogni specializzazione
di Uccello deve volare.
Nel caso dello Struzzo il metodo vola potrebbe essere:
...
chiama l'agenzia di viaggio
prenota un biglietto
vai all'aeroporto
prendi l'aereo
vola
... ;-)
MM

 il suo prezzo).
A me si: aveva un membro "etichetta con prezzo" appiccicata sopra. :-)
EMG

tutti gli schemi mentali che a fatica ci siamo costruiti fin'ora...
L'errore era solo in una errata analisi del problema, non certo ad un
qualcosa intrinseco alla OOP, anzi l'esempio portato e` probabilmente
uno di quelli che piu` di tutti avvicina gli oggetti della OOP a quelli 
della realta`.
Comunque rimettersi in discussione non e` mai un errore....
Paolo


cadrebbero nell'errore di dover magari rendere NOP il metodo Vola().
Qui` pero` era sbagliata l'analisi e non ha senso farvi riferimento in
questo contesto...
Paolo
P.s.
  Bella quella dello struzzo che prende l'aereo!      :)))))


 basic...
Che nostalgia...
A quei tempi 3,5 Kb liberi erano anche troppi!
--
Alessandro Monti

A quei tempi 3,5 Kb liberi erano anche troppi!
Il vic20 mi pare che di ram ne avesse anche meno!
Paolo


 Il vic20 mi pare che di ram ne avesse anche meno!
E se ricordo bene diminuiva ulteriormente se si faceva della grafica
troppo "spinta".
EMG

 Il vic20 mi pare che di ram ne avesse anche meno!
Non era il Sinclaire che ne aveva solo 1,5?
Ho ripreso in mano un libro sulla programmazione del Vic, ma non riesco a
trovare questa informazione.
Forse ricordo male, io avevo l'espansione che permetteva di arrivare
addirittura a 16K :-)
--
Alessandro Monti

Se non erro tra ram e rom il vic20 ne aveva 2KB!!!!
Le lotte per risparmiare i bit erano all'ordine del momento!!!!!
Ovviamente c'erano le espansioni, ma costavano un patrimonio.
Il commodore C16 invece aveva ben 16KB (sempre tra rom e ram)
che scendevano a 6KB se si passava alla modalita` grafica
(non ricordo se 2 o 4 colori e a quale risoluzione).
Ci feci un videogame lavorando con la grafica ed il basic... che tempi! 
Poi diventai "grande" e passai al mitico 286 (ben 12Mhz) con 1MB di ram
e 40MB di HD (con i commodore avevo il registratore a cassette), ma
questa e` un'altra storia!


 Ovviamente c'erano le espansioni, ma costavano un patrimonio.
Beh, non esageriamo. Il 6502 poteva indirizzare 64K, e anche escludendo
memoria video, indirizzi rubati dalle porte HW mappate in memoria (4k) e
tabella delle interruzioni, aveva comunque più di 2K, contando anche che
tutto il S.O. e l'interprete basic erano su ROM. (la memoria video invece su
RAM, non utilizzabile per i programmi, ma sempre RAM).
Il massimo di espansione possibile era di 16K (forse in aggiunta ai 3K di
un'altra schedina da usare con l'espansione multi-scheda), per cui risulta
che tra ram e rom ci fosse già installato:
64 - 4 (HW) - 16 = 44K
Magari c'è qualche K di differenza, ma non certo 42 come dici.
Potrei rileggermi i vari manuali del Vic20 per avere informazioni più
dettagliate, ma non credo che le cose cambierebbero di molto.
Io poi per passare a qualcosa di diverso ho dovuto passare direttamente al
286, escludendo qualche uso "improprio" su macchine altrui...
Se a qualcuno interessa, mi ero messo in testa di fare un emulatore del
Vic20. Qualcuno è interessato?
--
Alessandro Monti

Vic20. Qualcuno č interessato?
Non sarebbe una idea malvagia, ma a che servirebbe?
Io conservo ancora il registratore a cassette e alcuni programmi
(il vic20 ho fatto l'errore di venderlo, il c16 l'ho fuso!!!!!!),
ma come caricarli?


 ma come caricarli?
Servirebbe un "ponte" tra l'interfaccia del registratore e la
seriale/parallela (non mi ricordo come veniva fatto il trasferimento).
Io dovrei avere le specifiche elettriche, ma non sarei in grado poi di
costruire fisicamente il congegno.
Sarebbe veramente carino riesumare vecchi giochini. Considerando le risorse
a disposizione, erano fantastici.
Se mettessi (con calma) sul sito le informazioni che ho?
--
Alessandro Monti