Newsgroup: it.comp.lang.c++
Titolo: dubbio su covarianza

La possibilità di variare il return type nell'override di una funzione
membro vale anche se il tipo restituito non ha alcuna relazione con le
classi interessate? Mi spiego meglio con un esempio:
 struct Base { };
 struct Derived: public Base { };
 struct Astratta 
 {
     virtual Base* gimme() = 0;
 };
 struct Concreta: public Astratta
 {
     Derived* gimme() { /* ... */ }
 };
E' "legale" questo? gcc lo compila, MSVC no (ma sappiamo che non
supporta la covarianza del return type e quindi non fa testo).
Max

 ha scritto nel messaggio
news:Pine.LNX.4.10.100092...@c64.comm2000.it...

Si, è legale (affermazione approssimata alle mie conoscenze).
Comunque compila sia con il BCC 5.5 che con il KAI C++.
Manlio Perillo

classi interessate? 
Non sarebbe covarianza, il termine covarianza indica che il tipo dei
parametri e quello del valore restituito variano nella stessa
direzione (tipicamente verso sottoclassi).
Mancando una correlazione tra le classi interessate, non e` possibile
parlare di (co/contro)varianza.
Paolo
-------------------------------------------
  Paolo Marotta
 
http://web.tiscalinet.it/paolo_marotta/
-------------------------------------------

 direzione (tipicamente verso sottoclassi).
Qualcosa mi sfugge in quello che dici. Prima di tutto perchè parli di
parametri? Non ho lo standard ufficiale, ma nel draft si parla di
covarianza a proposito del return type, senza alcun riferimento al tipo
dei parametri.
Io ho sempre pensato che la "covarianza" avesse a che fare con il fatto
che che, se base::pippo() restituisce un base*, derived::pippo()  può
restituire un derived*.
Il mio problema era: che succede se, invece di un puntatore a
base/derived, pippo() vuole restituire un puntatore a un'altra gerarchia
di classi, diciamo base2/derived2, in modo che base::pippo() restituisca
un base2* e derived::pippo restituisca un derived2*?
Ora, come ho detto, io non ho lo standard e lo Stroustrup non sembra
parlarne, ma sono andato a vedermi il draft e ho trovato che
 If a function D::f overrides a function B::f, the return types of the
 functions are covariant if they  satisfy the following criteria:
 [...]
 -- the class in the return type of B::f is the same class as the  class
    in  the return type of D::f or, is an unambiguous direct or indirect
    base class of the class in the return type of D::f and is accessible
    in D
Nel prargrafo successivo c'è un esempio analogo a quello che avevo
sottoposto nel mio primo post, che quindi dovrebbe risolvere il mio
dubbio. E' possibile che lo standard abbia introdotto modifiche rilevanti
su questo punto...?
Max


Ecco... questa e` una definizione di covarianza, ma e` diversa da
quella che ho studiato io a suo tempo... dovrei approfondire!


interfacce, e un suo oggetto concreto restituisce tipi concreti.
Per fare questo non c'e' nessun problema: se la funzione e' dichiarata
restituire un puntatore a Base e tu supponiamo termini la funzione
con un
     return new Derived(...)
il puntatore viene semplicemente convertito a puntatore a base e
non ci sono problemi di sorta.
Il problema e' se vuoi che qualcuno possa chiamare la stessa
funzione e poi sfruttare l'informazione addizionale che l'oggetto
restituito e' un Derived e non un semplice Base (per esempio
chiamando metodi di Derived che Base non ha).
Mentre il primo caso di fabbriche che restituiscono puntatori
a oggetti astratti che in realta' puntano a oggetti concreti
derivati e' comunissimo se poi gli oggetti sono utilizzati
secondo l'interfaccia astratta (e quindi non serve la covarianza)
il secondo caso che a quanto pare ti interessa non credo mi
sia mai capitato.
Riguardo al supporto per questo utilizzo posso dire che il
seguente programma compila e funziona senza problemi su g++
(gcc version egcs-2.91.66 19990314 (egcs-1.1.2 release)) e
BCC55 ma genera un errore su VC++ 6.0
  #include <iostream>
 
  class B { };
  class D : public B { };
  class Base
  {
    public:
      virtual B* f()
      { std::cout << "Base::f()\n"; return new B; }
  };
  class Derived : public Base
  {
    public:
      virtual D* f()
      { std::cout << "Derived::f()\n"; return new D; }
  };
  int main()
  {
    Base *b=new Derived;
    delete b->f();
    return 0;
  }
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 
Infatti, questo è il punto. Ho posto la domanda perchè mi sono trovato in
una situazione in cui questa possibilità mi risultava estremamente utile.
Volevo infatti una classe astratta i cui metodi restituissero classi
astratte (come puntatori o reference, s'intende) e poterla implementare in
modo che i metodi corrispondenti restituissero classi concrete derivate
dalle quelle classi astratte. Ovvero: un'interfaccia restituisce
interfacce, e un suo oggetto concreto restituisce tipi concreti.
Al di là delle mie esigenze specifiche, che illustrare in questa sede
sarebbe troppo lungo e poco interessante, non mi pare che questo violi la
semantica della classe base visto che puntatori/reference a classi
derivate possono essere usate ovunque il codice si aspetti
puntatori/reference a classi base. Quanto all'effettiva utilità, è una
questione difficile da discutere in astratto.
Max

 BCC55 ma genera un errore su VC++ 6.0
Il tuo codice è perfettamente analogo a quello che avevo sottoposto nel
mio primo messaggio per spiegare cosa avevo in mente. Successivamente ho
scoperto che un frammento di codice pressocchè identico al nostro è
riportato come esempio nel draft. MSVC non supporta la covarianza
comunque, quindi il fatto che non lo compili non ci dice nulla. Manlio
Perillo ha detto di averlo compilato anche con il KAI, pertanto credo che
si possa a questo punto assumere che tutto ciò sia consentito dallo
standard.
Max


 parlare di (co/contro)varianza.
ne sei sicuro? prova a guardare questo codice:
class base
{};
class derived: public base
{};
struct A
{    base& f();}
struct B: public A
{    derived& f();}
beh, questa è covarianza! o sbaglio?

   }
Abbi pazienza, non riesco a capire questo passo:
delete b->f();
Chiami la funzione f() membro di Derived che restituisce un D* al D
appena creato che viene immediatamente rilasciato (delete). E già qui
non vedo il senso della cosa. Inoltre vorrei capire che fine fa b il
quale non viene mai rilasciato. Una dimenticanza?
EMG

quale non viene mai rilasciato. Una dimenticanza?
Volevo vedere se stavi attento... hehehe...
Ovviamente una dimenticanza. Nota che pero' abbandonare
oggetti sullo free store non e' "undefined behaviour"
o altro, anzi a volte e' una tecnica comoda che si
usa per risolvere il problema della dipendenza dall'ordine
di inizializzazione delle statiche (in particolare per
evitare altri problemi con l'ordine di distruzione delle
statiche).


 direzione (tipicamente verso sottoclassi).
non proprio: covarianza non mette in relazione tipi dei parametri ed il
tipo di ritorno: la covarianza indica che due tipi (composti) sono in
relazione (di sotto tipo) se i componenti sono in relazione allo stesso
modo; per i tipi di ritorno si ha la covarianza, mentre per i parametri
si ha la controvarianza (cioe' i componenti sono in relazione di
sottotipo nel verso opposto):
indicando con il tipo A -> B il tipo di una funzione che prende un
argomento di tipo A e restituisce un oggetto di tipo B, si ha la
seguente relazione di sottotipo (indicata con <:)
A -> B  <: A' -> B'
se
A' <: A
e
B <: B'
quindi la relazione di sottotipo per le funzioni e' COVARIANTE nel tipo
di ritorno e CONTROVARIANTE nel tipo del parametro. Di solito la
CONTROVARIANZA non e' molto utile nel tipo dei parametri e non viene
quasi mai implementata; se usi la COVARIANZA anche sui tipi dei
parametri il linguaggio non e' piu' type safe!
spero di aver chiarito le idee :-)
a presto
	Lorenzo
-- 
+-----------------------------------------------------+
|  Lorenzo Bettini          ICQ# lbetto, 16080134     |
|  PhD student in Computer Science                    |
|  Florence - Italy         (Linux User # 158233)     |
|  Home Page        : 
http://w3.newnet.it/bettini
     |
|           
http://infostud.dsi.unifi.it/~bettini
     |
|  Mail Home        : 
lorenzo...@penteres.it
     |
|  Mail University  : 
bet...@dsi.unifi.it
            |
|  
http://www.mokabyte.it
       Java on line journal  |
|  
http://music.dsi.unifi.it
         XKlaim language  |
|  
http://www.gnu.org/software/java2html
 & cpp2html   |
+-----------------------------------------------------+

beh, questa è covarianza! o sbaglio?
Certo, e` solo un caso limite essendo l'insieme dei parametri vuoto
(e qundi banale dimostrare che variano nello stesso senso del
tipo di ritorno).


quasi mai implementata;
Al contrario e` utilissima e assai sfruttata nei linguaggi con type
checking statico (C++ in primis, che implementa una controvarianza
parziale) perche` consente la verifica a compile time del
principio di sostituibilita` di Liskov.
La covarianza invece non permette di verificare tale principio se non
al costo di complicati algoritmi di analisi.
Paolo
p.s.
  Ricordo l'ottimo articolo di C. Pescio "Programmazione generica e
programmazione ad oggetti" (se non erro) che penso sia disponibile
su 
www.eptacom.net
Articolo che oltretutto riprende (almeno nel titolo) quello pressoche`
omonimo di B. Meyer


 omonimo di B. Meyer
Ho aperto l'articolo in questo momento ed ho visto il punto in cui parla
della controvarianza... penso che li' venga fatta un bel po' di
confusione (ti rimando alla citazione sopra).
Continuando a citare dall'articolo suddetto di Cardelli viene data una
definizione un po' piu' generale:
"In general we say that a type variable occurs contravariantly within
another type if it always occurs on the left of an odd number of arrows
(double contravariance equals covariance). For example, X -> Y and (Y ->
X) -> Y are contravariant in X, whereas Y -> X and (X -> Y) -> X are
covariant in X."
fammi sapere
a presto
	Lorenzo
P.S. questo thread mi prende un cifra, anche perche' mi piace molto
teoria dei tipi :-))) soprattutto applicata all'OOP


teoria dei tipi :-))) soprattutto applicata all'OOP
Ci mancherebbe  ;-)
Come informatici queste cose le mangiamo tutti i giorni.
Paolo

 sono di tipo puntatore.
Vuoi dire che questo è realmente fattibile in C++? Intendo: fare
l'override di una funzione specificando come argomento un supertipo
dell'argomento originale. Qualcosa come:
 struct A { };
 struct B: public A  { };
 struct base
 {
   virtual void f( B* a ) { std::cerr << "base" <<std::endl; };
  };
 struct derived: public base
 {
   void f( A* a ) { std::cerr << "derived" << std::endl; };
 };
Se ciò è previsto, nè MSVC nè gcc lo supportano, nel senso che non
vedono la seconda definizione come un override.
Max

 vedono la seconda definizione come un override.
Infatti era proprio questo il mio dubbio: io sapevo che non si poteva
fare in pratica in C++, nel senso che i compilatori non lo accettavano,
almeno fino a qualche tempo fa... non so cosa dice lo standard a
proposito.
ciao
	Lorenzo


 illogica.
se vuoi essere type safe l'UNICA possibilita' e' che il tipo del
parametro vari in modo controvariante ed il tipo di ritorno in modo
covariante. Solo (ripeto SOLO) in questo modo hai un subtyping che ti
permette la sostituibilita' di oggetti (nel caso di C++ riferimenti e
puntatori).
Linguaggi che permettono la covarianza sui tipi dei parametri NON sono
type safe (con type checking statico).
Si possono fare tranquillamente esempi di programmi che in questo caso
danno errori di tipo a run time (gli errori piu' temibili :-)
a presto


sono di tipo puntatore.
Sorry, ho preso un abbaglio. tuttavia ne VC++6.0 ne BCC5.5
si lagnano con il seguente codice:
class A {};
class B: public A {};
class C {
  public:
    A* Foo(B*) { return 0; };
};
class D : public C {
  public:
   B* Foo(A*) { return 0; };
};
se definisco le funzioni virtuali, allora BCC5.5 si lagna, ma VC no!
Paolo

 tipo di ritorno).
ehm, scusate, questo NG non era italiano?
scherzi a parte, questa (e il sottothread che prosegue dopo) me la ristudio
e quando l'ho capita ti rispondo ;). Eventuale letteratura al riguardo?

 
Perche' in questo caso si tratta di overloading: non ci sono problemi:
li' non si applica il binding dinamico, ne' il problema del subtyping,
ne' i discorsi di covarianza e controvarianza: quelli si applicano ai
metodi virtuali (overriding).


Perche' in questo caso si tratta di overloading: non ci sono problemi:
In realta` credo che sia un caso non lecito (dovrei verificare sullo
standard)...
Per quanto riguarda il discorso del C++, si parla di implementazione
parziale della controvarianza, solo perche` l'unico caso
ammesso e` quello del caso in cui si ritorni un puntatore.
Paolo

confusione
O forse no? :-)
Ciao,
Carlo

 2) riferiti al tipo _della funzione_.
Anche questa terza dizione è equivalente alle due di cui sopra? In
pratica "tipo di ritorno", "tipo del risultato di una funzione" e "tipo
della funzione" non significano esattamente la stessa cosa? Se no, mi
spiegheresti in cosa differiscono?
EMG

 standard)...
Non so se sia permesso dallo standard, pero'.
Intendevo dire che i problemi di type (un)safety ce li avresti col
binding dinamico, cioe' coi metodi virtual; altrimenti sei sicuro che
viene richiamato il metodo secondo il tipo di dichiarazione del
puntatore all'oggetto.
ciao


 O forse no? :-)
Ovviamente non intendevo offendere nessuno, soprattutto te :-) di cui
seguo sempre articoli e news letter
Mi riferivo al passo:
"Questa regola viene normalmente detta controvarianza, perché nella sua
formulazione piů generale (non implementata in C++), i parametri di f
potrebbero invece variare nel senso opposto, ovvero fare riferimento a
classi base rispetto a quelle specificate in Base::f."
Mi sarebbe sembrato piu' chiaro, secondo l'accezione (1), dire che c'e'
covarianza sul tipo di ritorno, e novarianza sul tipo dei parametri.
Del resto come hai detto tu, scegliendo l'accezione (1) si sarebbero
dovute spiegare molte piu' cose (oppure precisare in un riquadro), e le
limitazioni imposte sul numero di caratteri di un articolo sono sempre
una rottura di scatole ;-))))
Scusa per non aver precedentemente motivato la mia affermazione (non
volevo assolutamente apparire arrogante) :-)
a presto


 spiegheresti in cosa differiscono?
tipo della funzione inteso come: preso qualcosa di un certo tipo ritorna
qualcosa di un certo tipo, cioe' il tipo
A -> B
e' il tipo di una funzione che preso un argomento di tipo A restituisce
un tipo B
ciao


Perche' in questo caso si tratta di overloading: non ci sono problemi:
Solo un'aggiunta...
In questo caso non si puo` parlare di overloading poiche`
l'overloading e` definito tra funzioni in uno stesso namespace e una
dichiarazione di classe dichiara contestualmente anche un nuovo
namespace.
Se non ricordo per avere un overloading legale in quel contesto
si dovrebbe utilizzare una istruzione "using":
class C {
  public:
    A* Foo(B*) { return 0; };
};
class D : public C {
  public:
   using C::Foo;
   B* Foo(A*) { return 0; };
};
Questo discorso mi pare essere stato trattato tempo fa in
comp.lang.c++.moderated proprio con queste conclusioni.
Paolo

risultato".
Una domanda su questo punto...
Che senso ha parlare di varianza sul solo tipo di ritorno? [1]
O meglio, ha senso avere controvarianza stretta sul tipo di ritorno
(dato che la non varianza puo` essere vista come caso estremo della
covarianza e/o controvarianza). A occhio e croce direi che la
controvarianza stretta sul tipo di ritorno sia una violazione
del principio di sostituibilita`.
[1] Anche per questo io parlo di varianza riferendomi
      al tipo della funzione.
Paolo

spiegheresti in cosa differiscono?
Il tipo di una funzione ne comprende anche il dominio, il "tipo di
ritorno" e` invece il solo codominio.
Se hai una funzione che prende un parametro di tipo reale e
restituisce un naturale allora il suo tipo e` "R -> N", dove R e` il
dominio e N e` il codominio.
Ammetto che la distinzione tra "tipo di ritorno" e "tipo del
risultato" mi sfugge.
Paolo

Anche questa terza dizione è equivalente alle due di cui sopra? 
No: il tipo di una funzione comprende l'intera signature, quindi sia
il tipo dell'argomento che del risultato. In genere il tipo di una
funzione si indica con T1 x ... x Tn -> Tn+1, quindi la parte "di
sinistra", come dicevo nel posting precedente, e' il tipo
dell'argomento.
Ciao,
Carlo

 interfacce, e un suo oggetto concreto restituisce tipi concreti.
Non mi pare che la cosa abbia senso. Un'interfaccia che definisce un
contratto in termini di interfacce degli oggetti ritornati, e' utile
solo in quanto permette ai suoi clienti di astrarre dai tipi concreti
ritornati. Nel momento in cui un cliente ha necessita' di conoscere
questi tipi concreti, deve conoscere anche il tipo concreto che
implementa l'interfaccia originale, che diventa cosi' inutile.
In casi del genere puo' risultare piu' efficace utilizzare un template
al posto della tua interfaccia, parametrizzato sui tipi concreti degli
oggetti ritornati.
Ciao,
Nicola


Approfitto della tua domanda per completare un minimo il quadro.
Il problema della co/contro varianza a mio avviso ha due aspetti
interessanti: quello della validita' formale e quello dell'utilita'
pratica.
Siamo tutti d'accordo che supportare la controvarianza sulle funzioni
(o: covarianza sul risultato, controvarianza sui parametri) e' un modo
semplice per garantire la sostituibilita'. Ha anche una sua
ragionevole utilita', anche nella forma limitata del C++.
La covarianza sulle funzioni (o: covarianza su risultato e parametri)
dal punto di vista della utilita' pratica e', per molti, ancora piu'
importante (con tutto il baraccone dei binary method al seguito). Con
il "piccolo" problema di non _garantire_ con semplicita' un programma
type safe. Su questo punto credo che tu e Lorenzo Bettini non vi siate
ben capiti. Comunque, ci sono molti lavori che cercano di riconciliare
la covarianza con la type safety del programma (e' importante capire
bene che in presenza di covarianza delle funzioni, e' possibile dire
soltanto se ogni singolo programma e' type safe o meno a livello
complessivo, quindi con una analisi globale; si perde la
composizionalita' della type safety). 
Vi sono fondamentalmente due strade diverse, quella di Meyer
(piuttosto conosciuta attraverso i vari libri/articoli su Eiffel) e
quella forse un po' meno nota di Castagna. Per gli interessati,
riprendo un pezzettino da: John Boyland, Giuseppe Castagna, "Type-Safe
Compilation of Covariant Specialization: A Practical Case", Lecture
Notes in Computer Science 1098, 1996, che riassume i due approcci:
"The analysis for Eiffel answers the question: Is my program type-safe
even if I used covariant specialization? The problem addressed by this
article is substantially different. This work answers the question:
How can I change the semantics of my programs that use covariant
specialization in order to ensure type safety?".
[nota: Castagna nel pezzo citato usa "covariant" nel senso (2) del mio
post precedente, sottointendendo "dei parametri"].
Completando il quadro con la vera :-) risposta alla tua domanda. Un
programma che utilizzi la controvarianza sul tipo del risultato non ha
garanzie di type safety, esattamente come uno che utilizza la
covarianza sul tipo del parametro. A differenza di questo, tuttavia,
non sembra neppure avere una utilita' pratica, e per quello che so
dell'argomento, non e' neppure stato preso seriamente in
considerazione.
La domanda piu' interessante (almeno per me :-) diventa quindi: si
riesce a trovare un uso interessante della controvarianza sul
risultato (lasciando da parte il parametro, almeno per ora)? A naso (e
devo dire pensandoci per pochi minuti :-) non ho trovato niente, ma
forse a qualcuno piu' illuminato verra' in mente qualcosa. Se
diventasse utile, forse qualcuno si impegnerebbe per la giusta causa
:-) di studiare i casi di type safety, in analogia alla covarianza dei
parametri.
Ciao,
Carlo

 eventuali reply ci spostiamo sulla mail...
Trovo questo thread estremamente interessante e mi pare che speculazioni
del tipo "come sarebbe il C++ se questo aspetto funzionasse in
quest'altro modo" si possano considerare perfettamente in argomento,
certamente di piu' che non domande del tipo "Come faccio a creare un
bottoncino blu con la scritta in cirillico capovolta?".
Vi invito a proseguire la discussione sul newsgroup.
Ciao,
Nicola

 si dovrebbe utilizzare una istruzione "using":
Si' infatti in C++ devi utilizzare using proprio per le regole di
scoping e per il fatto che viene dichiarato un nuovo namespace.
a presto


 un tipo B
Ah, certo! Come dire che il tipo della funzione
int pippo( float f, char *p );
è
int ( float, char )
giusto? Ho capito bene?
EMG

 risultato" mi sfugge.
Appunto. :-)
EMG

 al solo tipo dell'argomento di una funzione".
Ok, ora è chiaro, grazie.
EMG

 composizionalita' della type safety).
io mi ero fatto un'idea a tal proposito, soprattutto dopo "Covariance
and Contravariance: Conflict without a Cause" di Castagna (premetto non
ho letto direttamente tale articolo: ho letto il tutorial di Castagna in
cui viene in pratica riproposto l'articolo quasi integralmente, ed ho
seguito un suo corso in cui ha affrontato l'argomento): si tratta
appunto di un conflitto senza una causa: la specializzazione covariante
sul tipo di ritorno e controvariante sul tipo dei parametri e' l'unica
possibilita' per avere type safety. Citando da Cardelli (Type Systems):
"Simple-minded reasoning reveals that this is the only sensible rule. A
function of type A -> B accepts elements of type A; obviously it also
acccepts elements of any subtype A' of A. The same function M returns
elements of type B; obviously it returns elements that belong to any
supertype B' of B. Therefore any function M of type A -> B, by virtue of
accepting arguments of type A' and returning reults of type B', has also
type A' -> B'. The latter is compatible with saying that A -> B is a
subtype of A' -> B'"
Pero' tornerebbe comodo avere anche la covarianza sul tipo dei parametri
come ad esempio nei binary methods. Castagna pero' dice appunto che e'
un "conflict without a cause" perche' in quel caso li' vorrei anche che
il metodo venisse richiamato a seconda del tipo attuale dei parametri,
cioe' mi servirebbe il multiple dispatching, in tal caso avrei anche
type safety senza problemi (il discorso era un po' piu' complesso
perche' comunque la classe derivata doveva fornire un'implementazione
anche per la signature della classe base).
Pero' piu' che specializzazione covariante a quel punto si tratta di
fornire nella classe derivata un metodo overloaded scelto pero' a
runtime (che e' comunque multiple dispatching). La regola di subtyping a
quel punto e' controvariante sui parametri sui quali non viene applicato
il multiple dispatching e covariante su quelli in cui viene applicato.
Non mi ricordo bene i termini che venivano usati nell'articolo (la
differenza era fra specializzazione ed un altro termine) (al momento non
ho l'articolo alla mano), pero' il succo se non ricordo male era questo.
Spero di non aver detto imprecisioni.
A quel punto anche il tipo di ritorno controvariante dovrebbe usufruire
di un controllo a run time (un multiple dispactching sul tipo di ritorno
(?))... 
effettivamente come dicevi tu e' un po' difficile vedere un'utilita'
pratica... uno dovrebbe voler la possibilita' di fornire in una class
derivata un metodo che puo' resistuire un oggetto (puntatore) di una
superclasse B se tale risultato viene assegnato ad un puntatore di tale
tipo oppure comportarsi normalmente (cioe' restituire un oggetto di
classe D, come da signature nella classe base)... a che puo' servire?
Magari perche' a quel punto il codice che chiama il metodo vuol
occuparsi di cose piu' a basso livello e, sapendo questa cosa e dovendo
restituire un oggetto di superclasse, il metodo invocato puo' effettuare
meno operazioni ottimizzando l'esecuzione? Mi sembra una notevole
forzatura :-)
Non so magari se eseguo:
Window *w = b->getDecoratedView() ;
con View derivata da Window, e' perche' magari mi voglio occupare di un
repainting particolare (mi voglio occupare di cose a piu' basso
livello), a quel punto, se b punta ad un oggetto di classe derivata, il
metodo getDecoratedView, che di solito restituisce View e si occupa
anche del repainting di tale view, rendendosi conto che gli viene in
realta' richiesta una Window puo' fare a meno di disegnare la View...
pero' mi sembra talmente artificioso come esempio e non so nemmeno se e'
sensato :-)))
Ovviamente per la type safety sto assumendo che si deve essere in grado
di testare a run time il tipo dell'oggetto a cui viene assegnato il
risultato.
ciao


int pippo( float f, char *p );
Esatto.
Paolo

 Vi invito a proseguire la discussione sul newsgroup.
Mi associo rumorosamente a Nicola.
EMG

 giusto? Ho capito bene?
ESATTO! Con un'altra notazione ma OK.
Probabilmente si tratta di una svista ma giusto per essere sicuri, la
forma corretta secondo la tua notazione sarebbe
int ( float, char * )


> Temo anche che quanto segue sia praticamente off-topic per il gruppo
(mi scuso con chi ne fosse infastidito). Forse e' meglio se per
eventuali reply ci spostiamo sulla mail...
e no!!! proprio adesso che cominciavo a capire qualcosa :-)! Secondo me
questi discorsi non sono assolutamente off-topic e non ne sono assolutamente
infastidito, anzi... vi pregherei di continuare.
-- 
Posted from [213.82.54.99] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 int ( float, char * )
Ovvio. Grazie.
EMG