<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2015-07-16 23:53 GMT+01:00 Enrico Bianchi <span dir="ltr"><<a href="mailto:enrico.bianchi@ymail.com" target="_blank">enrico.bianchi@ymail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 07/13/2015 11:55 AM, enrico franchi wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Il problema con l'overloading e' che rende un sacco di cose drammaticamente piu' complicate: in presenza dello stesso caso che menzioni (ovvero che non sai quale tipo sia una variabile) vuole dire che effettivamente il tuo codice compilera', ma tu non avrai idea di cosa faccia.<br>
</blockquote></span>
Mmm... non sono del tutto convinto, ovvero se io implemento Sum(int, int) e Sum(float, float), io so che posso avere o un int o un float e comportarmi di conseguenza<span class=""><br></span></blockquote><div><br></div><div>Allora, in Go, si, perche' non hai type cohercion. In altri linguaggi? Devi certamente ricordarti tutte le conversioni implicite. Per dire, in molti linguaggi un long chiamerebbe la versione per float invece che quella per int. Per dire... super intuitivo ;) Ricordati che i bachi hanno la tendenza a rendersi manifesti alle 2 di notte quando a guardare il problema c'e' tipicamente qualcuno che non e' l'ingegnere che ha scritto il codice.</div><div><br></div><div>E' un peccato che tu abbia tagliato il mio altro esempio che mostrava in modo completamente evidente quale sia il problema grosso (e che la mancanza di conversioni automatiche non e' sufficiente ad evitarlo). Se lo avessi studiato un pochetto ti saresti chiarito quale e' il punto.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Se non sai quale e' il tipo della variabile, vuole dire che non sai quale variante del metodo verra' chiamata. E quindi di fatto non sai che codice stai eseguendo. Ecco che un'innocua seccatura in assenza di overloading e' diventata una possibile fonte di bachi.<br>
</blockquote></span>
Mmm... In altre parole, stai dicendo che Python, in quanto (di solito) non sai il tipo della variabile masolo il suo contenuto, e` altamente problematico ;)</blockquote><div><br></div><div>Per assurdo molto meno. Almeno non ci sono dubbi su quale sia il codice della funzione che viene chiamato. Poi c'e' sempre il problema di quale sia il codice che la funzione che hai chiamato chiama a sua volta, ma quello fa parte del concetto di polimorfismo e tipicamente non vuoi farne a meno. E' un male quasi necessario.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
</blockquote></span>
Senza offesa, ma da come rispondi sembrerebbe che ti soffermi piu` sul codice che sul concetto che volevo esprimere. Quello che interessa a me e` fare il catch del panic, in quanto, ad esempio, potrei voler fare in modo che l'applicazione non debba terminare assolutamente la sua esecuzione se non tramite intervento manuale. La soluzione, come dico in seguito (e come ho scoperto proprio grazie a questo thread) e` usando recover() in una deferred function, che di per se non e` anche una cattiva soluzione, anche se limitata dalla gestione dei defer in Go (ovvero a cascata non appena la funzione viene eseguita completamente)</blockquote><div><br></div><div>Eh, ma se mostri codice per rappresentare il problema, ma il codice che mostri non rappresenta il problema io posso solo parlare del codice in se... la sfera di cristallo non mi funziona troppo bene. :)</div><div><br></div><div>Comunque, dipende come e' concepito il sistema. Ci sono casi in cui vuoi catturare un'eccezione piuttosto esterna. Tipicamente posso pensare ad un webserver essenzialmente stateless: fallisci la richiesta, tiri un 5xx e vai avanti. Essendo stateless, non hai il problema che il panic sia un sintomo di memoria corrotta. E se il sistema e' messo su da persone normodotate avrai un quache allarme se il rate di 5xx e' troppo alto (che indicherebbe a sua volta che il sistema e' compromesso e che bisogna intervenire). Quindi anche in questo caso devi comunque avere qualche tipo di supporto a livello di sistema/operations.</div><div><br></div><div>Su un sistema stateful in molti casi preferisco abbattere l'applicazione e non pensarci due volte. Tanto (sempre siccome parliamo di individui normodotati) il sistema avra' qualche tipo di ridondanza e questo non e' un problema. E ci sara' qualche tipo di nanny che ritira su il tutto (possibilmente partendo da uno stato non corrotto). Se ancora una volta l'applicazione va giu' troppe volte in poco tempo vuole dire che c'e' un problema, ci sara' un allarme e qualcuno dovra' correre a guardarci. Oppure se abbiamo abbastanza capacity (che so... siamo in N+K) ci si guarda il giorno dopo e tanti saluti. Nota, questo approccio funziona anche (e come sempre meglio) in un sistema stateless: semplicemente se hai stato catturare un'eccezione, loggare e andare avanti puo' volere dire che quell'istanza da quel momento in poi serve merda, hai un gray failure ed e' molto peggio: meglio abbattere tutto e tanti saluti.</div><div><br></div><div>Nel caso specifico di Go, ritirare su un'applicazione e' generalmente una cosa molto veloce. *E* i panic non dovrebbero segnalare condizioni "normali". Quindi e' assolutamente concepibile pulire tutto e fare morire e saluti.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Posso essere d'accordo, ma secondo me lo sconsigliare una pratica del genere e` difettata dalle varie casistiche. Vedi ad esempio il caso di un'applicazione che non deve morire mai</blockquote><div><br></div><div>Salvo che nel tuo caso l'applicazione moriva comunque. Tra l'altro mi aspetto che tu conosca la differenza fra except: ed except Exception:, quindi non vedo di cosa stiamo parlando. Quello che hai scritto *non* e' quello che vuoi nel 99.99% dei casi. Che e' il motivo per cui e' assodato essere una bad practice. :)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
a = may_return_null(...)<br>
if a is not None:<br>
f(a, ...)<br>
</blockquote></span>
Bruttino, non tanto perche` non mi piace, ma per com'e` scritto :)<br>
La sintassi<br>
if a:<br>
f(a,...)<br>
<br>
E` molto piu` elegante (si, e` una pulce che non serve a molto) :)</blockquote><div><br></div><div>No, serve: per ricordare a tutti di non fare come suggerisci. if a is not None e' una cosa molto diversa da if a:.</div><div>In un caso il mio problema especifico e' non avere None, nel secondo invece e' un puro "ValueError", ovvero non vuoi nulla che non valuti a falso. </div><div>Mi vengono in mente tanti casi in cui la stringa vuota e' un valore perfettamente legittimo che f deve sapere gestiere, mentre None, che non e' una stringa (e non ha i metodi delle stringhe) non puo' farci nulla.</div><div><br></div><div>Quindi, se vuoi escludere la stringa vuota (o 0, o la lista vuota, etc) usi l'idioma che suggerisci. Se vuoi escludere None, usi quello che suggerisco io.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Fanno sempre e solo stack unwind, non danno controllo al programmatore.<br>
</blockquote></span>
Mmm... continuo a non capire... Un esempio (o della documentazione)?</blockquote><div><br></div><div>Lisp.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Come dicevo... quello non e' Go idiomatico a mio avviso.<br>
</blockquote></span>
Anche qua, mi sembra che tu abbia dato piu` peso al codice che ho usato come esempio piuttosto che al concetto che volevo esprimere. Personalmente ritengo che un try/except sia piu` elegante rispetto al dover fare il check per ogni error che ti viene restituito. Quello che intendo e` che, ad esempio, le operazioni di apertura, scrittura e chiusura di un file in Go devono essere gestite una per una, mentre in Python le posso gestire tutte nello stesso try/except che, personalmente, ritengo piu` sensato</blockquote><div><br></div><div>E che e' esattamente quello che non dovresti fare. Certo, salvi un po' di caratteri. Poi e' 30 volte piu' complicato guardando un trace capire cosa e' successo e corri sempre il rischio di nascondere errori dietro ad altri errori. E ti trovi con quelle bellissime applicazioni che ad un certo punto si decide che e' ok che ogni tanto falliscano e che nessuno sa perche' finche', per caso, qualcuno non trova quale era effettivamente il problema (nella migliore delle ipotesi) o, nella peggiore, qualcuno mette pezze che non risolvono il problema ma lo mascherano ancora di piu.</div><div><br></div><div>In generale, se hai due linee che possono lanciare la stessa eccezione e tu hai un'azione da compiere su quell'eccezione, e' molto frequente che l'azione da compiere sia diversa. L'esempio tipico e' sui files... e' molto diverso avere un errore nella creazione di un file (o nell'apertura) oppure avere un errore nella read/write che segue tutto questo. Se poi dentro lo stesso blocco hai un loop... buona fortuna. Ottime probabilita' che qualcunque cosa stai facendo non sia transazionale.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Ancora peggio quando hai codice "lineare" del tipo fai una serie di operazioni una in fila all'altra. E hai errori vari che possono arrivare da ognuna di queste (possibilmente con un set di eccezioni non disgiunto per le varie chiamate).<br>
</blockquote></span>
Boh, a pensarci mi sembrano abbastanza semplici e pulite da gestire...</blockquote><div><br></div><div>O forse non stai pensando a tutti i failure mode che stai andando a nascondere...</div><div><br></div><div> </div></div>-- <br><div class="gmail_signature"> .<br>..: -enrico-</div>
</div></div>