Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esempio di interfacce #1

Open
MrPetru opened this issue Nov 8, 2012 · 5 comments
Open

esempio di interfacce #1

MrPetru opened this issue Nov 8, 2012 · 5 comments

Comments

@MrPetru
Copy link

MrPetru commented Nov 8, 2012

in questa posizione la funzione interno.Store() non ha niente collegato con il embedding dell'interfaccia interno.Storer in interfaccia Extender perché viene direttamente chiamata dal pacchetto "interno".

lo stesso embedding (Storer in Extender) può essere ignorato totalmente.
l'utilizzo dell'interfaccia Storer avviene nel modulo "interno", l'interfaccia stessa viene definita qui e la funzione Store ha come input un dato di tipo Storer. A questo punto, go non accerterà che alla funzione Store li sia passato un dato che non implementa questa interfaccia.
Quando nel pacchetto "medio" viene chiamata la funzione interno.Store(o) go verificherà se l'oggetto "o" implementa l'interfaccia interno.Storer cioè, verificherà se "o" ha implementata la funzione "ToStoreFormat() string" e questa accade qui. Quindi, la funzione interno.Store(o) viene soddisfatta al interno del pacchetto "interno" con la condizione che l'oggetto passato può esse usato come Storer. Risulta che l'embedding al interno del pacchetto "medio" non è necessario questo si può verificare tramite il commit 6a71769

@lento
Copy link
Contributor

lento commented Nov 9, 2012

questo e' un punto interessante!
Come il commit 6a717696a717693e459b2d79d49cfdeea114625a0294d13dimostra,
incorporare interno.Storer dentro medio.Extender non e'
necessario... eppure e' utile! :)
Vediamo come...
(ti allego il repo git modificato perche' qui a lavoro non ho la chiave ssh
per fare commit su github)
*
Perche' non e' necessario_:
In go un oggetto non deve "dichiarare" niente per implementare
un'interfaccia, e soprattutto non deve necessariamente "sapere" che sta
implementando un'interfaccia. Ogni oggetto con un metodo
*ToStoreFormat()implementa interno.Storer, anche se non e' dichiarato
esplicitamente,
quindi in quihttps://github.com/maponet/example/blob/4ccb6b1b66660c957d95d9693e059f3343dec6d8/medio/medio.go#L38possiamo
passare
o a interno.Store() perche' o e' un object e quindi ha un metodo *
o.ToStoreFormat()
.
Il programma compila e funziona, dal punto di vista dello sviluppatore che
usa *esterno.NewExtender()_ in esterno.go
https://github.com/maponet/example/blob/4ccb6b1b66660c957d95d9693e059f3343dec6d8/esterno/esterno.go,
e e' un ogetto di tipo medio.Extender, quindi se leggiamo la
documentazione dell'interfaccia sappiamo che abbiamo un metodo e.Save(),
lo chiamiamo e funziona.
Tutto bene? Quasi! :)

Perche' e' utile:
Ma cosa succede dal punto di vista dello sviluppatore che usa medio.go
(soprattutto noi stessi) se vogliamo definire un altro tipo che implementa
medio.Extender, per esempio un tipo advancedObject che usi un algoritmo
diverso quando richiamiamo SetPath() per assegnare il path?
Leggiamo la documentazione di Extender:

type Extender interface {
AddAttribute(name string)
SetAttribute(name, value string)
SetPath(p string)
Save()
}

Quindi definiamo il nostro SetPath() e** copiamo i metodi AddAttribute(),
SetAtttribute(), SetPath() e Save() di object cosi' come sono perche'
vogliamo modificare solo SetPath(), e abbiamo un Extender.
Modifichiamo NewExtender per ritornare un advancedObject invece di un *
object* e... il nostro programma non compila piu!

example/medio

medio/medio.go:71: cannot use a (type advancedObject) as type
interno.Storer in function argument:
advancedObject does not implement interno.Storer (missing
ToStoreFormat method)

L'errore ci indica chiaramente qual'e' il problema: advancedObject deve
essere non solo un Extender, ma anche uno Storer, ma lo scopriamo solo dopo
aver provato e riscontrato il problema di compilazione.
Se la documentazione ci avesse detto:

type Extender interface {
AddAttribute(name string)
SetAttribute(name, value string)
SetPath(p string)
Save()
interno.Storer
}

avremmo avuto una visione piu' precisa di cosa dobbiamo implementare.

Ti ho convinto? :)

2012/11/8 Petru [email protected]

in questahttps://github.com/maponet/example/blob/4ccb6b1b66660c957d95d9693e059f3343dec6d8/medio/medio.go#L38posizione la funzione interno.Store() non ha niente collegato con il
embedding dell'interfaccia interno.Storer in interfaccia Extenderhttps://github.com/maponet/example/blob/4ccb6b1b66660c957d95d9693e059f3343dec6d8/medio/medio.go#L6perché viene direttamente chiamata dal pacchetto "interno".

lo stesso embedding (Storer in Extenderhttps://github.com/maponet/example/blob/4ccb6b1b66660c957d95d9693e059f3343dec6d8/medio/medio.go#L11)
può essere ignorato totalmente.
l'utilizzo dell'interfaccia Storer avviene nel modulo "interno",
l'interfaccia stessa viene definita qui e la funzione Storehttps://github.com/maponet/example/blob/4ccb6b1b66660c957d95d9693e059f3343dec6d8/interno/interno.go#L9ha come input un dato di tipo Storer. A questo punto, go non accerterà che
alla funzione Store li sia passato un dato che non implementa questa
interfaccia.
Quando nel pacchetto "medio" viene chiamata la funzione interno.Store(o)https://github.com/maponet/example/blob/4ccb6b1b66660c957d95d9693e059f3343dec6d8/medio/medio.go#L38go verificherà se l'oggetto "o" implementa l'interfaccia interno.Storer
cioè, verificherà se "o" ha implementata la funzione "ToStoreFormat()
string" e questa accade quihttps://github.com/maponet/example/blob/4ccb6b1b66660c957d95d9693e059f3343dec6d8/medio/medio.go#L41.
Quindi, la funzione interno.Store(o) viene soddisfatta al interno del
pacchetto "interno" con la condizione che l'oggetto passato può esse usato
come Storer. Risulta che l'embedding al interno del pacchetto "medio" non è
necessario questo si può verificare tramite il commit 6a717696a71769


Reply to this email directly or view it on GitHubhttps://github.com//issues/1.

@MrPetru
Copy link
Author

MrPetru commented Nov 9, 2012

con il commit 3c623c4 riceviamo questi errory:

medio/medio.go:71: cannot use a (type advancedObject) as type interno.Storer in function argument:
    advancedObject does not implement interno.Storer (missing ToStoreFormat method)
medio/medio.go:79: cannot use o (type advancedObject) as type Extender in return argument:
    advancedObject does not implement Extender (missing ToStoreFormat method)

bene .... come risolviamo?
prima di continuare: concordo con il fatto che avendo il embedding in questa maniera è utile come "documentazione" ... ma non mi convince. Per ché ? noi chiamiamo Store() che si trova in un pacchetto che viene importato nel pacchetto corrente, allora è normale che io vado a vedere ( o già so come funziona il pacchetto importato e di conseguenza la funzione ) e vedo che alla funzione Store li si deve passare un oggetto che implementa l'interfaccia Storer altrimenti so che non posso usare quella funzione. e come "interno" non può conoscere niente che riguarda il suo importatore (medio) è normale che lui abbia definite le regole di comportamento al suo interno. Voglio dire che il comportamento di un oggetto viene definito li da dove si importa ma non dove è importato, e ogni volta che chiamo la funzione Store() prima vado a vedere cos'è e come funziona.
questo è stato un argomento non tanto forte ma credo che comunque valido.

il prossimo: cosi come abbiamo aggiunto al Extender "advancedObject" possiamo aggiungerne tanti altri ... possiamo aggiungere uno che invece di essere salvato in formato A (per esempio json) dovrà essere salvato in fomato B ( binario ) ... a questo punto l'Extender dovrà fare embedding con un altra interfaccia ... ma se questi convertitori dovranno essere di più? a questo punto fare embedding con una nuova interfaccia, significa o aggiungere delle funzioni vuoti per gli altri oggetti per soddisfare l'Extender o avere un software che di nuovo non funziona.

combinando la prima con la seconda: le interfacce vengono definite è documentate al interno del pacchetto importato. Alle funzioni usati in quel pacchetto li si passano dei oggetti che si implementano cosi che soddisfa la funzione chiamata.
per risolvere l'errore:

medio/medio.go:79: cannot use o (type advancedObject) as type Extender in return argument:
    advancedObject does not implement Extender (missing ToStoreFormat method)

basta non fare embedding del Extender con interno.Storer

per risolvere l'altro problema:

medio/medio.go:71: cannot use a (type advancedObject) as type interno.Storer in function argument:
    advancedObject does not implement interno.Storer (missing ToStoreFormat method)

dobbiamo cercare la documentazione della funzione Store() al interno del pacchetto "interno" e implementare advancedObject nella maniera giusta.

Cosi l'Extender rimane intatto anche nel futuro e potrà essere implementato da qualsiasi "advancedObject" senza rompere la compatibilità ... e ogni advancedObject potrà usare la sua interfaccia con personale cosi come sarà descritto al interno dei moduli usati. vedi il commit 1f0c00f

PS: questi commenti si vedono meglio su github, tramite email diventa illeggibile :(

@lento
Copy link
Contributor

lento commented Nov 9, 2012

il prossimo: cosi come abbiamo aggiunto al Extender "advancedObject" possiamo aggiungerne tanti altri ...
possiamo aggiungere uno che invece di essere salvato in formato A (per esempio json) dovrà essere salvato in
fomato B ( binario ) ... a questo punto l'Extender dovrà fare embedding con un altra interfaccia ... ma se questi
convertitori dovranno essere di più? a questo punto fare embedding con una nuova interfaccia, significa o
aggiungere delle funzioni vuoti per gli altri oggetti per soddisfare l'Extender o avere un software che di nuovo non
funziona.

questo e' il punto fondamentale della stratificazione:

  • interno "promette" a medio che potra' usare la funzione Store() per salvare nel DB oggetti che implementano Storer.
  • medio promette a esterno che potra' creare e settare attributi su oggetti che implementano Extender e salvarli in modo permanente con .Save().

il compito di decidere come salvare questi dati e' di interno, ed e' definito dall'interfaccia Storer. Ovviamente la definizione dell'interfaccia si evolve nella prima fase dello sviluppo a mano a mano che nuove esigenze vengono fuori, ma a un certo punto l'interfaccia verra' bloccata.
Nel nostro caso l'interfaccia e' bloccata e per implementare Storer un oggetto deve avere un metodo .ToStoreFormat che ritorna una stringa, e da quella stringa interno.Store() fara' quello che deve per salvare nel db.
Se in futuro dobbiamo cambiare il modo in cui i dati sono salvati, i cambiamenti saranno in Store(), e l'interfaccia Storer sara' preservata.

per risolvere l'errore: [...] basta non fare embedding del Extender con interno.Storer

sbagliato!
Questo non "risolve" l'errore, lo nasconde. Infatti se commenti quella linea ottieni un altro errore.
Per risolvere l'errore originario bisogna implementare ToStoreFormat().

Qual'e' la differenza tra ottenere il primo errore o il secondo?
Una volta che la compilazione e' fallita e' la stessa cosa, e go e' abbastanza furbo da indirizzarci correttamente in entrambi i casi.
Ma prima di fallire la compilazione

  • nel primo caso la necessita' di implementare ToStoreFormat() e' ESPLICITA (e' scritto nella documentazione dell'interfaccia Extender)
  • nel secondo caso e' IMPLICITA (se analizzi la documentazione di tutte le funzioni richiamate in tutti i metodi di object incontri interno.Store() e ricostruisci la necessita' di ToStoreFormat())

Che cosa e' meglio?

vedi il commit 1f0c00f

questo conferma il mio punto meglio di tutto quello che ho scritto! :)
In questo commit dimostri che devi implementare interno.Storer, ma nascondi la necessita'.

@MrPetru
Copy link
Author

MrPetru commented Nov 10, 2012

questo e' il punto fondamentale della stratificazione:

  • interno "promette" a medio che potra' usare la funzione Store() per salvare nel DB oggetti che implementano Storer.
  • medio promette a esterno che potra' creare e settare attributi su oggetti che implementano Extender e salvarli in modo permanente con .Save().

e fin qua sono d'accordo

il compito di decidere come salvare questi dati e' di interno, ed e' definito dall'interfaccia Storer. Ovviamente la definizione dell'interfaccia si evolve nella prima fase dello sviluppo a mano a mano che nuove esigenze vengono fuori, ma a un certo punto l'interfaccia verra' bloccata.
Nel nostro caso l'interfaccia e' bloccata e per implementare Storer un oggetto deve avere un metodo .ToStoreFormat che ritorna una stringa, e da quella stringa interno.Store() fara' quello che deve per salvare nel db.
Se in futuro dobbiamo cambiare il modo in cui i dati sono salvati, i cambiamenti saranno in Store(), e l'interfaccia Storer sara' preservata.

e anche qui sono d'accordo

la mia idea in questo momento è lasciare Extender a cura di medio e Storer a cura di Interno senza mischiarli ... cosi come ognuno risponde del suo. Ma come dici la definizione dell'interfaccia si evolve nella prima fase dello sviluppo a mano a mano che nuove esigenze vengono fuori ... e di questa ne sono certo, ne sono certo che la esigenza ci obbligherà a vere delle scelte ulteriore.

per risolvere l'errore: [...] basta non fare embedding del Extender con interno.Storer

sbagliato!
Questo non "risolve" l'errore, lo nasconde. Infatti se commenti quella linea ottieni un altro errore.
Per risolvere l'errore originario bisogna implementare ToStoreFormat().

Qual'e' la differenza tra ottenere il primo errore o il secondo?
Una volta che la compilazione e' fallita e' la stessa cosa, e go e' abbastanza furbo da indirizzarci correttamente in entrambi i casi.

questi errori non sono al inizio uno e poi l'altro ... sono tutti due contemporaneamente.
se la funzione seguente non esiste

func (a advancedObject) ToStoreFormat() string {
    fmt.Printf("\tmedio: execute ToStoreFormat\n")
    return "advancedObject formated"
}

gli errori sono:
1. NewExtender() Extender, non implementa l'Extender
2. a, o vero advancedObject, in interno.Store(a) non implementa interno.Storer

eliminando l'embedding, eliminiamo il primo errore o come dici tu, lo nascondiamo.... ma più che nascondiamo è facciamo in modo che al esterno ritorniamo un puro Extender.
il secondo errore è che dobbiamo implementare il interno.Storer per advancedObject ...

Ma prima di fallire la compilazione

  • nel primo caso la necessita' di implementare ToStoreFormat() e' ESPLICITA (e' scritto nella documentazione dell'interfaccia Extender)

questo è vero soltanto se qualcuno ha pensato a scrivere una documentazione completa per l'Extender ... da sola la riga interno.Storer non dice tanto è per capire che qui serve ToStoreFromat() si deve comunque trovare Storer nel pacchetto interno e leggerne la struttura per poi implementarla nel advancedObject. ma comunque sono d'accordo che è più diretto.

  • nel secondo caso e' IMPLICITA (se analizzi la documentazione di tutte le funzioni richiamate in tutti i metodi di object incontri interno.Store() e ricostruisci la necessita' di ToStoreFormat())

in questo caso (se capisco bene ... senza embedding ) si parte dalla premessa che devi usare interno.Store (per salvare i dati) ma per usarlo devi andare a leggere la documentazione nel interno, per capire che tipo di dato li devi passare. E da li capisci che li devi passare un oggetto che implementa un interfaccia Storer. Trovi Storer e in base alla sua definizione crei il dato necessario da passare a store.
Questo è un passaggio più lungo ma si arriva allo stesso risultato.

Che cosa e' meglio?

a me sembra che se la documentazione sarà scritta per bene, allora il primo va più che bene, ma se la documentazione sarà scarsa meglio usare il secondo passaggio, è più lungo ma anche più dettagliato.
c'è un problema in entrambi casi. ad un primo sguardo al oggetto advacedObject si vedrà la funzione ToStoreFormat() e non si capirà da subito per quale motivo è qui ... pero questa è magari per il semplice fatto che il nostro esempio non è tanto buono.

@MrPetru MrPetru closed this as completed Nov 10, 2012
@MrPetru MrPetru reopened this Nov 10, 2012
@MrPetru
Copy link
Author

MrPetru commented Nov 10, 2012

scusami avevo chiuso per sbaglio :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants