Newsgroup: it.comp.lang.c++
Titolo: Mostrami la preda

No, non e' un messaggio di spam, anche se la traduzione dall'inglese
"show me your catch!" perde un po' di senso.
Uno dei (tanti) problemi con le eccezioni e' il fatto che la
letteratura si focalizza su come non subirne le conseguenze piuttosto
che su come usarle con profitto. Questo e' in parte comprensibile,
perche' proprio per la non localita' intrinseca nell'uso delle
eccezioni la questione assume aspetti architetturali ed e' difficile
dare consigli sensati senza entrare nello specifico di ciascuna
applicazione.
Il punto fondamentale pero' mi sembra questo: cosa ci mettete nei
vostri catch? Siete in grado di mostrare esempi di clausole catch che
compiono operazioni non banali, appoggiandosi a informazioni
trasportate dall'eccezione intercettata?
La mia sensazione e' che le eccezioni vengano usate prevalentemente
per compiere logging, interrompere l'esecuzione o tornare al loop
principale dell'applicazione. Sbaglio? Per queste cose pero' le
eccezioni non servono.
Per quanto riguarda il logging si puo' avere l'impressione che le
eccezioni permettano di evitare di passare i meccanismi di logging
verso gli strati piu' bassi dell'applicazione, ma questo approccio
risulta inefficace nel momento in cui si vogliono memorizzare
informazioni relative a condizioni che non sono errori irrecuperabili;
per interrompere l'esecuzione c'e' assert e per tornare al loop
principale ci sarebbero setjmp/longjmp, se non fosse per il problema
dello stack unwinding.
Questo mi porta verso la convinzione che e' raro che ci siano motivi
per lanciare eccezioni che non siano di un generico tipo exception o
runtime_error; definire classi tipo divisione_per_zero o
radice_pari_di_valore_negativo solo perche' questi sono gli errori che
si vogliono gestire non mi pare molto sensato.
Invece motivi validi per definire una classe eccezione specifica
possono essere:
- Ci sono blocchi try che devono intercettare certe eccezioni e
lasciarne
  passare altre;
- Chi intercetta l'eccezione ha effettivamente bisogno di informazioni
  provenienti dal luogo di lancio;
- Puo' risultare comodo fattorizzare all'interno della classe
eccezione
  la costruzione del messaggio associato, ad esempio se si usa un'API
  che usa una convenzione particolare per segnalare gli errori.
Altri non me ne vengono in mente. Aspetto esempi delle vostre clausole
catch.
Ciao,
Nicola

 catch.
Vorrei aggiungere un'altra cosa. Parte del codice che scrivo è una 
libreria usata da altri programmatori in azienda. Codice critico e 
complesso, altrimenti non ci sarebbe vera necessità per la sua 
esistenza.
Qui ci sono due approcci guida.
Black box. In caso d'errore è la libreria che prova a metterci una 
pezza, oppure alza le mani in segno di resa. Chi la usa non può farci 
niente.
Consapevole. In caso di errore è chi la usa che deve fare qualcosa di 
sensato per correggere ed eventualmente rimuovere la causa d'errore. 
Ovviamente in questo caso deve *sapere* come gira il motore sotto il 
cofano.
Bisogna intendersi prima su cosa sia un errore, e poi di quali di 
questi due approcci, nei propri casi specifici, si deve intraprendere. 
Da questo deriva anche una possibile scelta di come far "galleggiare" 
l'errore.
Per dire, se io uso una libreria di JPEG, e non so una mazza di JPEG, 
se questa mi manda un eccezione, o mi ritorna un codice d'errore, il 
mio comportamente sarà il medesimo: non so cosa farci.
Quindi vorrei aggiungere, quanti scrivono codice che non è usato 
esclusivamente da loro, come si comportano con gli "errori" e le 
eccezioni?
-- 
http://aratriel.wordpress.com/2007/11/05/in-lavorazione-il-primo-teaser-trailer-di-star-trek-2008/

 catch.
Avevo già accennato a due casi in cui io ho trovato comodissimo 
utilizzare le eccezioni. Un caso, secondo me abbastanza interessante, è 
un parser di un formato ASCII. Il parser è scritto in modo da prendere 
in input un istream, così può essere utilizzato anche quando il file da 
parsare arriva direttamente sullo stdin e non da un file ordinario. 
D'altra parte il caso più comune è invece aprire un file e poi passare 
lo stream al parser.
Quando leggi un file in un formato "umano", devi gestire gli eventuali 
errori sintattici. Inoltre devi dare all'"umano" che li ha scritti 
qualche indicazione sul tipo di errore e la posizione dell'errore.
Inoltre, visto che è possibile parsare molti file in un unico batch, 
bisogna anche indicare il nome del file che ha dato l'errore, ed 
eventualemente continuare a processare gli altri file, scartando solo 
quello errato.
In tutto questo l'uso delle eccezioni è molto naturale. Il parser si 
basa su un tokenizer. Il tokenizer può esso stesso trovare degli errori. 
Per il parser sarebbe molto noioso dover intercettare tutti gli errori 
del tokenizer, è molto più semplice scrivere il codice del parser dando 
per scontato che il file sia ben formato. Dunque il tokenizer può 
lanciare delle eccezioni che il parser lascia passare. Il parse può pure 
lanciare le sue eccezioni. Entrambe queste eccezioni utilizzando una 
classe apposita in cui è memorizzata una descrizione dell'errore e il 
numero di  riga in cui è stato trovato.
La funzione che parsa un file di cui viene dato il nome, può catchare le 
eccezioni del parser, aggiungerci il nome del file e rilanciarle.
Il programma principale ha diverse modalità di utilizzo. Può essere 
utilizzato da riga di comando oppure come CGI. A seconda dei casi 
gestisce l'errore nel modo migliore. In particolare se è un CGI, non può 
brutalmente terminare, bisogna che completi l'eventuale pagina HTML 
chiudendo tutti i tag rimasti aperti, deve visualizzare un errore per 
l'utente collegato da remoto e mandare un'errore su stderr che verrà 
memorizzato nel LOG del server web.
E.

   che usa una convenzione particolare per segnalare gli errori.
Concordo anche qui.
Aggiungo che sto usando libpqxx e sarebbe utile poter capire 
dall'eccezione generata, qual'e' l'esatto problema che la query ha 
avuto. Purtroppo questo non sempre e' possibile... ma sono molto 
all'inizioe e spero di essere io a non aver ancora capito esattamente il 
modo giusto.
  bye
	av.

  eccezioni?
Capitato, ora capita meno.
Il codice doveva stare in una libreria dinamica, ed essere il piu'
possibile portabile (almeno linux/windows).Eliminate le eccezioni, e
fatta un'interfaccia c-style.
Fa brutto dirlo in un newsgroup di C++, ma viste le premesse ho
realizzato che era l'unica via praticabile.
Per tornare al topic, nei casi in cui ho potuto usare le eccezioni, le
ho usate solo nel modo "1" di Nicola, per filtrarne alcune e lasciarne
andare altre (in gerarchie di eccezioni di 2-3 livelli di profondita').
--*PaN!*
 
-- 
I'm using an evaluation license of nemo since 164 days.
You should really try it!
http://www.malcom-mac.com/nemo

Le eccezioni sono un meccanismo per gestire gli errori, e' chiaro che
ci sono delle alternative come assert o goto, e le exception sono la
proposta object oriented a quei meccanismi.
il vantaggio di usare eccezioni personalizzate
( argument_must_be_child_of_a_rabbit_Exception ) esiste solo quando
alla libreria che le lancia e' abbinata una documentazione completa di
dove e come queste eccezioni possano essere sollevate.
mi e' capitato infinite volte di dover catturare un eccezione ma, non
sapendo che roba fosse, ho usato la classe generica :/

 sapendo che roba fosse, ho usato la classe generica :/
Spesso semplicemente non c'e' bisogno di distinguere perche' non
esistono azioni di recupero distinte per diversi tipi di eccezione.
Ciao,
Nicola

 catch.
Anche per astrarre l'uso dell'errore, secondo la problematica sopra
esposta...

 Nicola Musatti ha scritto:
[...]

Continuo a non essere convinto che le eccezioni siano un buon modo di
rappresentare il fatto che una funzione non e' definita
sull'argomento. Trovo meglio utilizzare un valore convenzionale oppure
un tipo annullabile. In questo caso specifico per esempio penso che
ritornerei un "quiet" NaN, altrimenti qualcosa del tipo di
boost::optional<double> .
Devo pero' dire che prima di leggere il tuo post avrei anche preso in
considerazione l'uso di assert per verificare la positivita'
dell'argomento, mentre ora mi rendo conto che non e' sempre una buona
idea.
Ciao,
Nicola

 idea.
Il concetto di fondo è che non esiste mai una regola d'oro. Dato che la
programmazione è uno strumento, deve conformarsi alle esigenze.

 Questo a prescindere dalle implementazioni, comunque.
in effetti matematicamente non è gradevole il NAN (che starebbe 
a significare una stringa di bit non inizializzata e quindi non 
interpretabile come numero, nel senso di formattata come non senso).
Però, dato che diversamente dagli interi, nel formato IEEE dei 
vari double NON tutte le combinazioni di bit sono comunque 
significative, non è che ci siano alcune configurazioni di bit 
che non corrispondono a numeri float normalizzati, ma pur sempre 
  numeri ? Penso ad esempio se sia possibile mappare in valori 
confrontabili (con qualche operatore o funzione apposita), del 
tipo UNDERFLOW, OVERFLOW, e così via.
Un diviso zero imho ci starebbe bene come un +o- infinito, ossia 
un overflow ...
Invece ho qualche difficoltà a immaginare il valore di ritorno 
di una radice pari di una quantità negativa, che senza scomodare 
un bit di status "immaginario" non rientrano molto bene nelle 
eccezioni di calcolo con infiniti.
Qualcuno ha esperienza con uso dei calcoli floating point dove 
si possano eseguire confronti coi valori critici, denormalizzati 
e ogni altra rappresentazione non ordinaria degli stessi ?
Detto altrimenti, il linguaggio di alto livello, ha 
rappresentazioni confrontabili (o testabili con roba tipo 
IsEqual o altro) con NaN, Overflow, Underflow e quant'altro esiste ?
ciao
Soviet


 Overflow, Underflow e quant'altro esiste ?
Conosco _isnan _finite e _fpclass che dovrebbero far parte della 
libreria run time del C (almeno ci sono nei compilatori MS)
GM

 IsEqual o altro) con NaN, Overflow, Underflow e quant'altro esiste ?
Si, vedi ad esempio: 
http://www.dinkumware.com/manuals/default.aspx?manual=compleat&page=math.html#isnan
Ciao,
Nicola

 esponente non coerenti, o è diverso ?)
E' un numero in virgola mobile in cui la cifra piu' significativa
della mantissa e' zero.
Ciao,
Nicola

 Ora chiedo, se è la prima, una delucidazione su cosa intendono dire
Questa e' documentazione, non codice. Specifica che isnan in C deve
espandersi in un rvalue intero, mentre FP_NAN deve espandersi in
un'espressione intera costante. Non dice niente su come ottenere
questi valori, che chiaramente dipendono dalla piattaforma.
Ciao,
Nicola

 Nicola

 della mantissa e' zero.
In particolare serve per rappresentare numeri in valore assoluto molto
piccoli che non sarebbero altrimenti rappresentabili.
-- 
cc = callcc {|cc| cc.call cc}; cc.call cc

 boost::optional<double> .
In questo caso anche io ritornerei NaN. Principalmente perchè è un
valore *apposta* creato per gestire casi come questi. Non a caso per
dirne una frsrte (un'istruzione PPC per la radice quadrata) ti da
proprio NaN se la chiami su un operando negativo.
Ma se invece siamo negli interi? Definiamo la funzione solo sugli interi
senza segno, e siamo a posto. Ok, l'esempio non calza, in effetti.
Che so... hai una funzione che accetta solo numeri dispari. Ovviamente
non puoi restringere il dominio a priori. Per cui che fai?
Usi boost::optional? Si. Funzionare funziona. Però hai una sintassi
oggettivamente più pesante. Inoltre potresti avere casi in cui *sai* per
certo che stai chiamando una funzione con argomenti corretti (per
proprietà esterne del codice). 
Con le eccezioni puoi non mettere nulla, il boost::optional te lo porti
dietro comunque. Nota bene che non è che sono contrario. Dipende molto
dal caso.
Ribadisco: una funzione che dato nome e cognome ti va a prendere dal db
un impiegato mi parrebbe molto strana con un boost::optional. Tanto più
che comunque possono capitare guai di connessione e molto altro. Alla
fine devo comunque gestire le eccezioni, e tanto vale.
IMHO, eh. Certo, non è un problema di dominio. 
