View Full Version : [ALL] Curiosita' sui flusso di controllo di un programma
Scusate, spesso mi imbatto in situazioni in cui devo eseguire una serie di operazioni all'interno di un "task" piu' generale e spesso l'operazione i-esima deve essere eseguita solo se la precedente e' andata a buon fine.
Per esempio ho un task generico che per coerenza logica e' suddiviso in 4 operazioni A, B, C e D. Ogni operazione e' ovviamente una funzione.
Ad esempio:
- A = lettura di un file con i dati di connessione
- B = connessione ad un db
- C = esecuzione select
- D = lettura recordset ottenuto
Ognuna di queste 4 operazioni dipende dal successo della precedente (vabbe' a parte la prima che va sempre eseguita...).
Sinceramente a me fa abbastanza schifo scrivere codice del tipo:
if(A)
if(B)
if(C)
if(D) ...
else errore D
else errore C
else errore B
else errore A
Anche perche' non sempre le cose sono cosi' lineari.
Vorrei sapere se voi seguite degli schemi precisi o meno. Questa e' una questione piuttosto sottovalutata in programmazione ma alla fine la "ciccia" dei nostri programmi e' proprio costituita da tutti quei brutti IF, SWITCH, WHILE, FOR... di cui anche la programmazione ad oggetti prima o poi necessita.
wingman87
17-03-2010, 18:30
Con il meccanismo delle eccezioni (se disponibile) puoi scrivere codice più elegante e leggibile:
try{
A
B
C
D
}catch(Errore){
Gestione Errore
}
Beh non e' necessariamente corretto e produttivo l'uso delle eccezioni per la gestione degli errori. Le eccezioni generalmente vanno lanciate e catturate per gestire situazioni "eccezionali" appunto, cioe' imprevisti.
Nelle situazioni a cui faccio riferimento, come nell'esempio, io vorrei che B venisse eseguita solo se A va a buon fine, ma A potrebbe benissimo ritornare errore per un motivo piu' che lecito e per nulla "eccezionale". Cioe' non sempre le operazioni falliscono per motivi inconsueti.
Per esempio l'operazione C dell'esempio (select su db) potrebbe semplicemente ritornare null perche' non trova alcun record, ma questo non significa che si debba lanciare un'eccezione!
Per chiarire meglio, il mio codice nel caso presentato e' spesso cosi:
try
{
if(A)
if(B)
if(C)
if(D) ...
else errore D
else errore C
else errore B
else errore A
}catch(Errore){
Gestione Errore
}
Cioe' le operazioni sonno "immerse" quasi sempre in un try-catch in modo da poter gestire situazioni impreviste. Ma le operazioni possono fallire per situazioni prevedibilissime che nulla hanno a che fare con le eccezioni.
Mah non saprei... è prevedibile che un sistema di risoluzione dei nomi (tipo DNS) possa non trovare alcun record relativo ad un URL?
A mio parere si, eppure nei moderni linguaggi di programmazione questa viene considerata una eccezione.
La regola è che tutto funzioni come dovrebbe, l'eccezione è proprio un caso che non ti consente di andare avanti nel programma di per se.
Nel tuo caso:
- A = lettura di un file con i dati di connessione
- B = connessione ad un db
- C = esecuzione select
- D = lettura recordset ottenuto
A e B possono essere tranquillamente gestite tramite eccezioni.
In C l'esecuzione della select per quale motivo dovrebbe fallire, supponendo che la query sia pre-confezionata e ben formata?
Stessa cosa per D, NULL non è un fallimento.
Qui il piano si sposta su cosa consideri come fallimento... supponendo che per C e D valgano le mie considerazioni, non ci sarebbe alcun motivo di fare un controllo su queste due cose.
Chiaramente in fase di presentazione dei risultati il discorso è diverso, in quanto eventuali record NULL potresti volerli evitare (adesso non ricordo se i ResultSet scartano in automatico i record NULL, in quel caso non dovresti fare controlli, in genere le routine di presentazione ciclano sulla base della dimensione del ResultSet, che in questo caso sarebbe nulla).
E' chiaro che questo è un esempio, come dici te ci si può trovare spesso nella situazione di dover effettuare più controlli concatenati, e se non vuoi ricorrere alle eccezioni credo che quello sia l'unico modo.
Una cosa che ho trovato comoda per levare un po' di if di mezzo è usare ove possibile il polimorfismo, chiaramente non si può usare sempre questa via (ad esempio in questo caso poco c'entrerebbe), però in alcuni casi può essere la soluzione.
Se usi un linguaggio OO la questione non si pone. Ogni linguaggio orientato agli oggetti è un meta-linguaggio. Significa tra l'altro che sei sempre libero di definire un approccio alla soluzione di un problema che esula dalle operazioni predefinite.
Bisogna avere un'idea alternativa, un "sarebbe bello se potessi scrivere così".
Come si potrebbe esprimere una catena di if in modo non annidato? Si potrebbe usare un concatenatore di espressioni, qualcosa cioè che data una lista di espressioni esegua la successiva solo se la precedente abbia dato un certo risultato. Diremmo allora:
a = if x qualcosa else qualcos'altro
b = if x qualcosa else qualcos'altro
...
z = if x qualcosa else qualcos'altro
concatenatore esegui a + b + ... + z
Non è difficile pensare a come si possa realizzare. Abbiamo semplicemente un'espressione composta di una condizione e due alternative che restituisce un valore di controllo, diciamo un booleano. L'espressione restituisce true se la condizione è true altrimenti esegue l'alternativa e restituisce false. Il concatenatore piglia queste espressioni e dice:
per ogni espressione x se x.eval restituisce true esegui la successiva altrimenti termina.
Tutto sta nello scegliere una soluzione: il resto lo fa l'orientamento agli oggetti.
sadino90
17-03-2010, 19:49
Non basta definire un metodo per A che ritorna un valore booleano per indicarne l'esito?
Così puoi tranquillamente scrivere
if(A)
B
E come dice WarDuck per C e D non occorrono controlli
Beh non e' necessariamente corretto e produttivo l'uso delle eccezioni per la gestione degli errori. Le eccezioni generalmente vanno lanciate e catturate per gestire situazioni "eccezionali" appunto, cioe' imprevisti.
Direi di no. Le eccezioni servono proprio per la gestione degli errori.
Le situazioni "eccezionali" sono invece quelle non previste e quindi non gestite se non, solitamente, da un try catch in cui è contenuto il ciclo principale del programma. Java differenzia proprio bene questa situazione con le checked e le unchecked exception.
Beh veramente tutto quello che ho letto sulle eccezioni generalmente diceva proprio di evitare di utilizzare le eccezioni per la gestione degli errori comuni e prevedibili.
In ogni caso non volevo focalizzarmi su un esempio preciso, ma piuttosto su una "best practice" comune. E' innegabile infatti che generalmente un sistema software complesso presenta innumerevoli operazioni composte da altre operazioni e cosi' via, creando un annidamento non banale.
Proprio per questo generalmente le best practice per l'exception handling dicono di gestire le eccezioni il piu' vicino possibile al punto in cui vengono generate.
Questo implica chiaramente che non si puo' utilizzare un unico try-catch a livello del main, ma invece occorre avere un blocco try-catch quasi in ogni metodo-operazione sufficientemente complessa da poter generare molte situazioni anomale e impreviste.
E questo e' un altro punto fondametale. Infatti gran parte delle funzioni-metodi corposi a mio parere devono avere una gestione moltro stretta degli errori, cioe' gestire tutto il piu' localmente possibile e soprattutto bisogna sempre supporre che per quanto siamo stati bravi, potrebbe essere generato un errore imprevisto anche dopo mesi che il software e' in stato di release.
Nell'esempio che ho fatto, volutamente semplice, vorrei farvi notare che, sì, e' vero che una semplice select difficilmente fallisce, ma ripeto, volevo cercare di rendere l'idea con un piccolo esempio, non focalizzarmi su quello. In una situazione reale qulle operazioni A-B-C-D magari al loro interno sono molto piu' complesse e a loro volta sono suddivise in sotto-operazioni, anch'esse da eseguirsi in sequenza una dopo l'altra.
E' innegabile quindi che non e' possibile fare in modo che qualunque metodo in caso di errore lanci un'eccezione piuttosto che gestire localmente l'errore. Questo puo' essere corretto solo per pochi casi isolati, ma in genere, questo sistema di "scarica barile" sul chiamante prima o poi deve terminare con un try-catch piu' generale, e se tutti i metodi fanno lo scarica barile... l'unico try-catch che gestisce tutto e' sul main... e quello poverino non ne sa piu' nulla dell'errore e non fa altro che dire "HEY.. ERRORE!". E tanti saluti.
scusate, non leggo il thread ma do ugualmente la mia risposta.
Ognuna di queste 4 operazioni dipende dal successo della precedente (vabbe' a parte la prima che va sempre eseguita...).
Sinceramente a me fa abbastanza schifo scrivere codice del tipo:
if(A)
if(B)
if(C)
if(D) ...
else errore D
else errore C
else errore B
else errore A
Anche perche' non sempre le cose sono cosi' lineari.
Vorrei sapere se voi seguite degli schemi precisi o meno. Questa e' una questione piuttosto sottovalutata in programmazione ma alla fine la "ciccia" dei nostri programmi e' proprio costituita da tutti quei brutti IF, SWITCH, WHILE, FOR... di cui anche la programmazione ad oggetti prima o poi necessita. questione interessantissima: mi ci sono imbattuto anche io qualche anno fa e ho trovato la miglior soluzione nel design pattern degli scoped objects del C++. quando dichiari variabili automatiche in uno scope, lo standard del C++ garantisce che i distruttori verranno invocati in ordine inverso rispetto all'ordine di dichiarazione (e quindi inverso rispetto all'ordine di invocazione dei costruttori), il che ti permette ad esempio di tradurrre questo codice:
if (inizializzazione di A riuscita con successo) {
if (inizializzazione di B riuscita con successo) {
if (inizializzazione di C riuscita con successo) {
esegui operazione che usa A, B e C;
cleanup di C;
} else {
errore relativo a C;
}
cleanup di B;
} else {
errore relativo a B;
}
cleanup di A;
} else {
errore relativo ad A;
}
in questo, molto migliore IMO:
class A {
public:
A() {
if (inizializzazione di A fallisce) {
throw false;
}
}
~A() {
cleanup di A;
}
};
class B {
public:
B() {
if (inizializzazione di B fallisce) {
throw false;
}
}
~B() {
cleanup di B;
}
};
class C {
public:
C() {
if (inizializzazione di C fallisce) {
throw false;
}
}
~C() {
cleanup di C;
}
};
{
A a;
B b;
C c;
esegui operazione che usa a, b e c;
}
Beh veramente tutto quello che ho letto sulle eccezioni generalmente diceva proprio di evitare di utilizzare le eccezioni per la gestione degli errori comuni e prevedibili.
Java non la pensa così: http://java.sun.com/javase/6/docs/api/java/sql/DriverManager.html#getConnection(java.lang.String)
Quello è uno dei casi da te proposti ;)
Poi dipende sempre cosa si intende per "situazione eccezionale". Secondo me le eccezioni vanno usate in tutti i casi in cui la mancata esecuzione di una operazione abbia implicazioni nel proseguimento di una sequenza di operazioni che si suppone il chiamante esegua. L'esempio della connessione al database è proprio una di queste.
Altrimenti uso la normale gestione degli errori con il ritorno di boolean.
Comunque le possibilità possono essere molteplici, dipende molto anche da chi programma le varie operazioni. Se lo facessi io penserei ad una classe con le varie operazioni di ripulitura...
Che so, una cosa del genere:
UndoInfo undo;
bool doSomething(...., UndoInfo &undo)
{
if(!x.a(..., undo))
{
return false;
}
if(!x.b(..., undo))
{
return false;
}
if(!x.c(..., undo))
{
return false;
}
return x.d(..., undo));
}
UndoInfo undo;
if(!doSomething(...., undo))
{
undo.cleanUp();
}
Se uno vuole fare il figo (anche se si perde in leggibilità):
bool doSomething(...., UndoInfo &undo)
{
return x.a(..., undo) && (x.b(..., undo) && x.c(..., undo) && x.d(..., undo));
}
Ogni operazione su x aggiungerà le relative operazioni di clenup ad UndoInfo. Il modo in cui si possono aggiungere dipende molto dal linguaggio:
- per linguaggi interpretati si aggiungeranno stringhe che poi verranno interpretate con la relativa funzione eval
- per altri linguaggi si dovrà implementare un'interfaccia ed inserire il method object all'interno di UndoInfo.
UndoInfo::cleanUp non dovrà fare altro che eseguire in ordine inverso rispetto all'inserimento le varie operazioni di clean up
class A {
public:
A() {
if (inizializzazione di A fallisce) {
throw false;
}
}
~A() {
cleanup di A;
}
};
class B {
public:
B() {
if (inizializzazione di B fallisce) {
throw false;
}
}
~B() {
cleanup di B;
}
};
class C {
public:
C() {
if (inizializzazione di C fallisce) {
throw false;
}
}
~C() {
cleanup di C;
}
};
{
A a;
B b;
C c;
esegui operazione che usa a, b e c;
}
Sicuramente ha senso, però io tendo a fare generalmente costruttori passivi, che si limitino esclusivamente ad inizializzare le variabili membro. Questo per vari motivi:
- i costruttori si debuggano peggio
- mi piace vedere invocato un metodo che descriva l'esatta operazione che sto facendo
- i costruttori si debuggano peggio perché? io non ho mai incontrato simili difficoltá, se faccio step into il debugger mi entra regolarmente nel costruttore prima di proseguire e se metto un breakpoint nel costruttore il debugger mi ci si ferma regolarmente.
edit - parlo del debugger di Visual C++ :D
- mi piace vedere invocato un metodo che descriva l'esatta operazione che sto facendo gusti, a me va bene anche vedere le tre dichiarazioni tenendo presente la semantica del C++.
anzi, di un linguaggio mi piace sfruttare tutti i meccanismi.
perché? io non ho mai incontrato simili difficoltá, se faccio step into il debugger mi entra regolarmente nel costruttore prima di proseguire e se metto un breakpoint nel costruttore il debugger mi ci si ferma regolarmente.
edit - parlo del debugger di Visual C++ :D
Sì, anche gdb ci entra, ma a volte la cosa produce alcuni effetti collaterali antipatici.
Succede a volte, ma non voglio rischiare...
gusti, a me va bene anche vedere le tre dichiarazioni tenendo presente la semantica del C++.
anzi, di un linguaggio mi piace sfruttare tutti i meccanismi.
Sì, però se guardi alla definizione di costruttore, soprattutto quello di default, in teoria si dovrebbe limitare a "costruire" la classe. Eventuali funzionalità sono insite nei costruttori specializzati, che poi, solitamente, non fanno altri che andare a richiamare un metodo della stessa classe.
Di esempi ce ne sono a bizzeffe, ma anche se si va a vedere il pattern Method Object (cioè un oggetto con un solo metodo), l'implementazione non è mai nel costruttore, ma anche per ovvi motivi: non potrei passare l'oggetto per valore perché eseguirei due volte l'operazione, oppure eseguirei l'operazione quando non mi serve.
tomminno
18-03-2010, 19:28
in questo, molto migliore IMO:
class A {
public:
A() {
if (inizializzazione di A fallisce) {
throw false;
}
}
~A() {
cleanup di A;
}
};
class B {
public:
B() {
if (inizializzazione di B fallisce) {
throw false;
}
}
~B() {
cleanup di B;
}
};
class C {
public:
C() {
if (inizializzazione di C fallisce) {
throw false;
}
}
~C() {
cleanup di C;
}
};
{
A a;
B b;
C c;
esegui operazione che usa a, b e c;
}
Mi dispiace deluderti ma se gli scoped object rappresentano (o dovrebbero esserlo) una pratica comune in C++, un costruttore che solleva eccezioni invece non lo è, e anzi è altamente sconsigliato.
Ovviamente non sono io a dirlo ma un certo Herb Sutter http://www.gotw.ca/gotw/066.htm di cui consiglio: Exceptional C++ e More Exceptional C++.
Il primo risultato è che non verrà mai chiamato il distruttore in quanto l'oggetto ha vita solo alla fine del costruttore ma se questo solleva un'eccezione non termina correttamente.
Un costruttore che solleva eccezioni ti porta ad usare i function try block in altre classi. I function try block sono obbligati a risollevare un'eccezione quindi ciò comporta che rischi di non portare a termine la costruzione di un'intera collezione di oggetti, nell'esempio tutte le classi che abbiano come variabile d'istanza un oggetto di tipo A o B o C e così ricorsivamente.
Ovvero rischi di ritrovarti al catch nel main:
class ThrowChild
{
public:
ThrowChild()
{
throw exception("faccio terminare il programma");
}
};
class NoThrowChild
{
public:
NoThrowChild() try :tc(){}catch(...){throw exception("Houston abbiamo un problema"); }
private:
ThrowChild tc;
};
class MainNoThrow
{
public:
MainNoThrow() {}
private:
NoThrowChild ntc;
};
int main(int argc, char *argv[])
{
try
{
MainNoThrow nt;
}
catch(const exception & ex)
{
cout << ex.what() << endl;
exit(-1);
}
catch(...)
{
exit(-1);
}
return 0;
}
di cui consiglio: Exceptional C++ e More Exceptional C++.
Caspita, 'sto tizio è proprio stupefatto da C++. Il terzo volume come l'ha chiamato? C++ ecceziunale veramente?
rеpne scasb
18-03-2010, 21:20
■
tomminno
18-03-2010, 21:59
Caspita, 'sto tizio è proprio stupefatto da C++. Il terzo volume come l'ha chiamato? C++ ecceziunale veramente?
Exceptional C++ Style :D
Questo "tizio" è stato fino a tutto il 2008 il capo del comitato per la standardizzazione del C++.
Io ripeto secondo me che il problema è "a monte", ovvero verificare effettivamente cosa si possa definire "eccezione", e soprattutto se è il caso di fare un certo tipo di controlli per quelle parti di codice il cui comportamento è ben determinato.
Io ripeto secondo me che il problema è "a monte", ovvero verificare effettivamente cosa si possa definire "eccezione", e soprattutto se è il caso di fare un certo tipo di controlli per quelle parti di codice il cui comportamento è ben determinato.
Esatto
In effetti le soluzioni sono molte per il semplice fatto ci sono infinte possibilità di complicare le cose. Quello che mi sembra strano è che non ci sia fondamentalmente una best practice per lo meno ufficiosa (se non ufficiale).
La gestione degli errori tramite eccezioni a mio parere e' utile solo in funzioni di libreria abbastanza generiche.
Secondo me infatti il modello delle eccezioni e' sostanzialmente uno "scarica barile" sul chiamante. E prima o poi qualcuno il barile deve per forza sobbarcarselo, cioe' qualche metodo-funzione deve prima o poi fare una catch e gestire l'errore. E quello a quel punto manda a farsi friggere il modello stesso della gestione degli errori tramite eccezioni.
Infatti quel metodo in caso di errore, invece di lanciare un'eccezione al chiamante a sua volta (come tutti gli altri metodi) deve gestire l'errore localmente nella calusola catch, sia che si tratti di errori generati da eccezioni lanciate da funzioni all'interno del corpo del metodo in questione, sia che si tratti di errori propri del metodo.
A quel punto al questione si sposta su "scegliere il metodo che gestisce l'errore". E' questo e' difficile, tanto difficile che alla fine ci si riduce a mettere il try-catch nel main. E alla fine nel main dell'errore non se ne sa una mazza ormai, perche' magari generato 10 livelli piu' sotto. L'unica cosa che si puo' fare e' mostrare un messaggio di errore con tutta lo stack trace!
Con le eccezioni esplicite lo scaricabarile non c'è, o al limite è voluto. Se si usa throws in Java (fortunatamente ti obbliga a farlo) e throw in C++ (accanto alla firma del metodo) non ci sono di questi problemi, perché l'eccezione sei obbligato a gestirla o al limite ad usare gli stessi throw e throws accanto alla firma del metodo chiamante.
Non concordo sul fatto che la gestione e l'implementazione delle eccezioni sia utile solo in funzioni di libreria.
Io tra l'altro penso che un programma serio vada organizzato a moduli e che ogni modulo sia di fatto trattato come una libreria. Per questo penso sempre ad un modulo di un programma come un insieme coerente e di fatto ai fini esterni simile ad una libreria in cui gli utilizzatori sono gli altri moduli.
tomminno
19-03-2010, 09:53
La gestione degli errori tramite eccezioni a mio parere e' utile solo in funzioni di libreria abbastanza generiche.
Secondo me infatti il modello delle eccezioni e' sostanzialmente uno "scarica barile" sul chiamante.
Perchè la gestione degli errori tramite codice di ritorno non lo è?
Con la differenza che puoi sempre ignorare un codice di ritorno, ma non un'eccezione.
Considera poi che tutti i metodi del .NET ma anche di Java ti ritornano delle eccezioni se non riescono ad eseguire per un qualunque motivo ovvero o hai il risultato desiderato o hai una eccezione.
Oh oh attenti... non sto mica dicendo di non usare le eccezioni!
La verita' e' che il modello delle eccezioni impone un lavoro massivo da parte del programmatore per gestire tutte le possibili eccezioni generabili. Di conseguenza cosa succede?
Succede che se il metodo che genera le eccezioni e' una libreria di terzi, il programmatore finisce per ingoiarsi tutte le eccezioni con un unico catch Exception generico, che sostituisce magari 10 catch ognuno per ciascuna eccezioni generabile dal metodo in question (e Java con le checked exception ti costringerebbe a farlo, a differenza di tutti gli altri linguaggi).
Se il metodo e' stato fatto dal programmatore stesso, quello finira' per far lanciare al metodo un'unica eccezione personalizzata per tutti i possibili errori in cui il suo metodo puo' incorrere, invece che creare un'eccezione per ciascuno di essi. E questo alla fine equivale a ritornare un booleano di controllo.
Insomma la verita' e' che le eccezioni sono una fantastica idea che pero' e' efficacemente applicabile solo nel piccolo (o nella teoria!). Nella pratica, con applicazioni medio-grandi si finisce sempre per usare un unico catch Exception o, se possibile (non in Java), non fare alcun catch se non nel main.
E questo non lo sostengo solo io sia chiaro, ma anche Bruce Eckel, i designer del C#...
Personalmente mi piacerebbe riuscire a trovare un sistema di programmazione che mi faccia gestire in maniera pulita gli errori, senza costringermi a sporcare il codice con una miriade di catch come fa Java con le checked exception. Ma non l'ho ancora trovato...
Non voglio salire in cattedra anche perchè mi fa male un ginocchio ma un conto è un errore, un conto è un'eccezione.
Entrambi sono condizioni che determinano l'impossibilità logica per un blocco di codice di essere eseguito.
L'errore è una condizione certa sia nel quando sia nel se.
x = 0
y = 10
z = y / x;
L'eccezione è "certa an, incerta quandum": sai quando si verifica ma non sai se si verificherà:
funzione divide(x, y) = x / y;//eccezione
Tutte le eccezioni dovrebbero essere controllate - altrimenti non ha senso averle. E' difficile - ma non impossibile - giustificare la presenza di eccezioni non controllate se non per l'atto pratico di voler evitare il sovrappiù di intercettazioni dovute all'uso di funzioni particolarmente frequenti (ad esempio la dereferenziazione).
tomminno
19-03-2010, 13:37
Tutte le eccezioni dovrebbero essere controllate - altrimenti non ha senso averle.
Ti riferisci alle checked exception di Java o al fatto di dover fare il catch di ogni tipologia di eccezioni sollevata?
Nel primo caso ci sono forti discussioni sull'utilità delle checked exception (in .NET hanno deciso consciamente di non impiegarle) che diventano oltretutto parte integrante della firma di un metodo e in caso di refactoring sono dolori. Nel secondo caso invece in una manciata di chiamate a metodi del runtime sia esso Java o .NET dovresti mettere tanti di quei catch da diventare scemo. Ogni metodo ti solleva almeno un paio di eccezioni differenti, non è raro trovare metodi che ritornano 6 o più eccezioni. Ma quando li uso, una volta che so che quella chiamata è fallita, quasi mai mi interessa il motivo specifico, in ogni caso non saprei come porvi rimedio, mi sembrano non proprio comuni i casi in cui a seconda del tipo di eccezione si debbano compiere azioni differenti.
La prima, vale a dire che mi riferisco all'obbligatorietà della gestione delle eccezioni.
La quantità di catch che uno dovrebbe mettere è irrilevante.
Considera che ci sono alcune situazioni in cui Java rilascia eccezioni non controllate che sarebbe stato preferibile gestire in modi diversi. Ad esempio la NullPointerException rilasciata ad ogni dereferenziazione si inquadrebbe bene nel sistema dei tipi (con un'opzione o un supertipo "NotNull").
Non è andata così. Come disse Gosling, a un certo punto dovemmo rilasciare quel che avevamo senza poter appronfondire.
Quanto a NET non è un buon esempio di alcunchè.
Sì, anche gdb ci entra, ma a volte la cosa produce alcuni effetti collaterali antipatici.
Succede a volte, ma non voglio rischiare... :mbe:
Sì, però se guardi alla definizione di costruttore, soprattutto quello di default, in teoria si dovrebbe limitare a "costruire" la classe. quale definizione?
Eventuali funzionalità sono insite nei costruttori specializzati, che poi, solitamente, non fanno altri che andare a richiamare un metodo della stessa classe. é una possibile filosofia, io non aderisco: nel codice di un costruttore ci si puó mettere qualunque cosa e io ci metto quello che secondo me conviene metterci.
Di esempi ce ne sono a bizzeffe, ma anche se si va a vedere il pattern Method Object (cioè un oggetto con un solo metodo), l'implementazione non è mai nel costruttore, ma anche per ovvi motivi: non potrei passare l'oggetto per valore perché eseguirei due volte l'operazione, oppure eseguirei l'operazione quando non mi serve. veramente no perché passando l'oggetto per valore viene usato il costruttore di copia, non quello di default, peró l'osservazione porta la mia attenzione ad un problema effettivo: se il costruttore di copia viene usato accidentalmente il distruttore dealloca due volte la stessa risorsa, ed é un errore. quindi il codice che ho scritto prima va aggiornato cosi (tenendo presente che quando si vieta l'uso del costruttore di copia nella stragrande maggioranza dei casi si vieta l'uso anche dell'operatore di assegnazione per gli stessi motivi):
class A {
private:
A(const A&) {}
A &operator = (const A&) { return *this; }
public:
A() {
if (inizializzazione di A fallisce) {
throw false;
}
}
~A() {
cleanup di A;
}
};
class B {
private:
B(const B&) {}
B &operator = (const B&) { return *this; }
public:
B() {
if (inizializzazione di B fallisce) {
throw false;
}
}
~B() {
cleanup di B;
}
};
class C {
private:
C(const C&) {}
C &operator = (const C&) { return *this; }
public:
C() {
if (inizializzazione di C fallisce) {
throw false;
}
}
~C() {
cleanup di C;
}
};
{
A a;
B b;
C c;
esegui operazione che usa a, b e c;
}
ed effettivamente riconosco che inizia ad essere un codice un po' prolisso a cui forse si potrebbe preferire il catenaccio di if, ma questo codice puó comunque avere una grossa utilitá se si prevede di fare riuso delle classi A, B e C, cioé se le semplificazioni che esse apportano superano l'overhead sintattico.
[...] Il primo risultato è che non verrà mai chiamato il distruttore in quanto l'oggetto ha vita solo alla fine del costruttore ma se questo solleva un'eccezione non termina correttamente. infatti non mi aspetto che venga chiamato il distruttore, ma mi aspetto che vengano chiamati i distruttori dei sotto-oggetti che il costruttore é riuscito a creare.
Un costruttore che solleva eccezioni ti porta ad usare i function try block in altre classi. I function try block sono obbligati a risollevare un'eccezione quindi ciò comporta che rischi di non portare a termine la costruzione di un'intera collezione di oggetti, nell'esempio tutte le classi che abbiano come variabile d'istanza un oggetto di tipo A o B o C e così ricorsivamente.
Ovvero rischi di ritrovarti al catch nel main: [...] posso conviverci. quello che dice Herb Sutter é giusto, un essere umano non puó esistere se non esiste qualcuno dei suoi organi, e se pure riuscisse ad esistere non sarebbe propriamente un essere umano. non mi aspetto che se la costruzione di un sotto-oggetto fallisce l'oggetto principale debba continuare ad esistere, io cerco di dare corrispondenza concettuale ai miei programmi, se un mio oggetto contiene un sotto-oggetto é perché non puó farne a meno. se un'architettura del genere in un mio programma causa l'arrivo di un eccezione addirittura fino al main evidentemente é mia opinione che il mio programma non possa funzionare per niente senza quel sotto-sotto-...-oggetto.
d'altra parte invece allocare le risorse in un metodo di inizializzazione a parte dal costruttore mi complica il programma perché introduce la possibilitá che l'oggetto si trovi in due stati diversi: inizializzato e non inizializzato. non mi conviene quasi mai.
Con la differenza che puoi sempre ignorare un codice di ritorno, ma non un'eccezione. come no? catch block vuoto e prosegui.
Non è obbligatorio gestire le eccezioni, per questo il punto è decidere cosa vuoi che il programma faccia in caso di errore.
Un esempio pratico di un programmino che ho fatto per controllare se un sito web è stato aggiornato (fa una request ogni tot secondi e controlla se la data del sito web è uguale alla precedente).
Supponi che io disponga di una form in cui inserire l'URL, ora ho queste possibilità:
- Controllare se l'url è ben formato in fase di inserimento, in caso contrario impedire che venga attivata la routine di controllo.
- Dare per buono ciò che l'utente inserisce e gestire eventuali eccezioni.
Ci sono casi in cui si è obbligati a seguire la seconda strada, ad esempio attivando la routine di controllo non puoi sapere a priori se il DNS troverà un riscontro per l'URL inserito.
Cosa succede se il sito web esiste ma la connessione cade?
Sapendo che il sito web esiste devo dedurre che si tratta di un problema "momentaneo", quindi potresti scegliere di ritentare tra tot tempo piuttosto che interrompere il programma.
In questo caso è chiaro che io da utente preferirei che si occupasse il programma di gestire questa situazione.
Non sempre tuttavia è possibile gestire gli errori e la sintassi di alcuni linguaggi non aiuta in questo (non si riesce ad evitare di aggiungere codice "superfluo", anche lì dove non serve).
veramente no perché passando l'oggetto per valore viene usato il costruttore di copia, non quello di default
Vero :doh:
Non è solo in questo caso che sei obbligato a scrivere il costruttore di copia e l'operatore =. Con la tua filosofia oltre al costruttore attivo hai anche il distruttore attivo e di conseguenza con il distruttore attivo sarai obbligato ad implementare anche costruttore di copia e operatore =.
Riguardo alla definizione: il costruttore definisce un modo per inizializzare un oggetto (questa a memoria è la definizione di Stroustrup). Quindi in teoria dovremmo metterci dentro solo l'inizializzazione.
Implementando il costruttore di default che fa solo l'inizializzazione, potrai anche implementare i costruttori specializzati in modo attivo. Questo perché comunque ci sarà un modo per inizializzare in modo passivo l'oggetto e quindi sarai obbligato a gestire questa possibilità nel distruttore.
Secondo me la tua non è una filosofia, ma è proprio un errore concettuale.
Entrambi sono condizioni che determinano l'impossibilità logica per un blocco di codice di essere eseguito.
Per questo ho scritto che gestirei con le eccezioni solo situazioni in cui un errore possa far fallire una sequenza di operazioni che mi aspetto che il chiamante faccia oltre alla corrente.
Capisco il senso di errore in quella frase ma va precisato che nel contesto delle eccezioni "eccezione" ed "errore" sono mutualmente esclusivi: sono due tipi diversi di condizioni (che determinano l'impossibilità eccetera eccetera).
L'errore di cui parli è, presumo, un fatto esterno al programma - come può essere lo stato di un server http.
L'esempio da cui prendevo l'ispirazione è proprio la connessione ad un DB e l'esecuzione di una query.
Quanto a NET non è un buon esempio di alcunchè.
Conoscere ciò di cui si parla prima di parlarne è un ottimo modo per evitare di dire stronzate (cit)
Io so sempre di cosa parlo :Prrr:
Io so sempre di cosa parlo :Prrr:
Si', certo. Come no :D
Comunque, giusto per aggiungere qualcosa alla discussione, per coloro che intendessero mai scrivere prima o poi dei test per le proprie applicazioni ( :p )
uno dei parametri principali per stimare la complessita' di una funzione e quindi la sua difficolta' di copertura e' la complessita' ciclomatica
http://it.wikipedia.org/wiki/Complessit%C3%A0_ciclomatica
Che non ha nulla a che fare con la complessita' computazionale. (le notazioni O(n) e Θ(n)). La complessita' ciclomatica da un'indicazione su quanti branches diversi di codice l'escuzione potrebbe potenzialmente suddividersi, e quindi su quanto e' difficile coprire completamente una funzione con tutti i test necessari per eventualmente scoprire qualche anomalia.
Piu' la complessita' ciclomatica e' alta e piu' saranno necessari test per la copertura.
Esistono tool di test aid che dichiarano, tra le altre cose, la complessita' ciclomatica di ogni metodo del proprio codice (NCover per C#, JTest ma anche altri per Java).
Tali software sono anche molto utili per un altro parametro: la percentuale di copertura dei test che sono stati scritti, le percentuali di copertura per ogni metodo (rimando a wiki per il significato delle diverse percentuali date per ogni pezzo di codice - http://en.wikipedia.org/wiki/Code_Coverage) e la possibilita' di scoprire quali sono le righe di codice eventualmente non ancora coperte dai propri test. Quando si raggiunge 100% non significa comunque purtroppo che il software e' immune da test, proprio a causa della complessita' ciclomatica. Alcuni pezzi di codice devono essere testati appunto piu' volte.
Da esperienze dirette, sebbene il significato operativo sia lo stesso, per ridurre la complessita' ciclomatica il precedente pezzo di codice sarebbe meglio scriverlo come segue:
if (!A)
{
Errore A
Return
}
if (!B)
{
Errore B
Return
}
if (!C)
{
Errore C
Return
}
if(D)
{
Errore D
Return
}
Codice che non a caso assomiglia parecchio all'uso delle Guards di check iniziale.
Ecco un esempio visuale da parte di un collega indiano che spiega l'operazione e anche altri motivi.
http://technorati.com/videos/youtube.com/watch%3Fv%3DQGfXoSxBOJQ
Se tali condizioni non fossero funzioni, ma solo e semplicemente proprieta' con i loro valori, ovvero se si e' in presenza di puri e semplici controlli iniziali (e FINALI) del valore di alcune proprieta' allo scopo di eseguire o meno il metodo (le guards appunto), si suggerisce l'uso delle direttive di "Design by Contract"
Tali direttive sotto C# verranno supportate da un plug-in di VS2010, e saranno semplicemente attributi.
I benefici operativi li tralascio (Alcuni errori possono addirittura essere catturati in fase di complilazione, piu' controllo in fase di debug, ...)
Il beneficio prinicipale nel Test Driven Developement e' proprio l'abbassamento della complessita' ciclomatica, e quindi il minor numero di test necessari, e quindi il poter dormire piu' tranquillamente quando si modifica un codice e si ha paura di regression bugs altrimenti potenzialmente molto difficili da scoprire. http://en.wikipedia.org/wiki/Regression_testing
Qui maggiori info sul Design By Contract, e il concetto di PreConditions (le guards appunto) e PostConditions e alcuni dei vantaggi possibili.
http://www.codeproject.com/KB/cs/designbycontract.aspx
PS: Ma ste cose, ad ingegneria informatica, le spiegano oggi? Spiegano qualcosa, almeno l'esistenza, dell'Extreme Programming, dell'Agile programming etc.?
Oppure sono ancora fermi a spiegare Waterfall, Incremental e soci, che non usa piu' nessuno?
Da esperienze dirette, sebbene il significato operativo sia lo stesso, per ridurre la complessita' ciclomatica il precedente pezzo di codice sarebbe meglio scriverlo come segue:
if (!A)
{
Errore A
Return
}
if (!B)
{
Errore B
Return
}
if (!C)
{
Errore C
Return
}
if(D)
{
Errore D
Return
}
leak-prone
Il beneficio prinicipale nel Test Driven Developement e' proprio l'abbassamento della complessita' ciclomatica, e quindi il minor numero di test necessari, e quindi il poter dormire piu' tranquillamente quando si modifica un codice e si ha paura di regression bugs altrimenti potenzialmente molto difficili da scoprire. http://en.wikipedia.org/wiki/Regression_testing senti, lascia proprio perdere che in questo forum ci sono un po' di persone che hanno visto in maniera molto diretta i risultati :asd:
PS: Ma ste cose, ad ingegneria informatica, le spiegano oggi? Spiegano qualcosa, almeno l'esistenza, dell'Extreme Programming, dell'Agile programming etc.? da me si, a Ingegneria del Software, ma siccome ho scoperto che quel corso mi fa schifo l'ho tolto dal piano di studi :asd:
PS: Ma ste cose, ad ingegneria informatica, le spiegano oggi? Spiegano qualcosa, almeno l'esistenza, dell'Extreme Programming, dell'Agile programming etc.?
Oppure sono ancora fermi a spiegare Waterfall, Incremental e soci, che non usa piu' nessuno?
Spero che insegnino informatica e non stregoneria.
Parlando di cose serie e visto che siamo in tema, tempo fa lessi di una società o neozelandese o australiana o che altro (è stato tempo fa e io ho quel tanto di alzheimer...) che aveva sviluppato un software accompagnato dalla prova matematica dell'assenza di bug. Naturalmente essendo una cosa interessante ho perso il link e non trovo la combinazione di parole per ripescarla con un motore di ricerca. Qualcuno l'ha per caso letta e può mettere il link qui?
wingman87
20-03-2010, 13:52
PS: Ma ste cose, ad ingegneria informatica, le spiegano oggi? Spiegano qualcosa, almeno l'esistenza, dell'Extreme Programming, dell'Agile programming etc.?
Oppure sono ancora fermi a spiegare Waterfall, Incremental e soci, che non usa piu' nessuno?
A informatica (non ingegneria) dove vado io sì, nel corso di ingegneria del software (che nel mio indirizzo è obbligatorio, in altri no).
wingman87
20-03-2010, 13:54
Spero che insegnino informatica e non stregoneria.
Parlando di cose serie e visto che siamo in tema, tempo fa lessi di una società o neozelandese o australiana o che altro (è stato tempo fa e io ho quel tanto di alzheimer...) che aveva sviluppato un software accompagnato dalla prova matematica dell'assenza di bug. Naturalmente essendo una cosa interessante ho perso il link e non trovo la combinazione di parole per ripescarla con un motore di ricerca. Qualcuno l'ha per caso letta e può mettere il link qui?
Esistono metodi di sviluppo formali (e relativi strumenti, ad esempio il linguaggio Z) che permettono di farlo (visto sempre nel corso di "stregoneria" :Prrr:)
stregoneria è riferito a extreme-agile-testdriven developement e/o programming.
wingman87
20-03-2010, 14:07
stregoneria è riferito a extreme-agile-testdriven developement e/o programming.
Ah, ok, non avevo capito, sorry. Comunque due giorni fa mi è arrivato un libro di java sui metodi agili, "Agile Java" di Jeff Langr, e non sembra male.
Spero che insegnino informatica e non stregoneria. PGI, non dirlo troppo in giro ma... ti amo :stordita:
senti, lascia proprio perdere che in questo forum ci sono un po' di persone che hanno visto in maniera molto diretta i risultati :asd:
Il Test Driven Develpment permette di avere ottimi risultati. I problemi di Diamonds sono stati altri.
da me si, a Ingegneria del Software, ma siccome ho scoperto che quel corso mi fa schifo l'ho tolto dal piano di studi :asd:
Peccato perché è stato uno dei corsi più importanti del mio piano di studi.
Parlando di cose serie e visto che siamo in tema, tempo fa lessi di una società o neozelandese o australiana o che altro (è stato tempo fa e io ho quel tanto di alzheimer...) che aveva sviluppato un software accompagnato dalla prova matematica dell'assenza di bug. Naturalmente essendo una cosa interessante ho perso il link e non trovo la combinazione di parole per ripescarla con un motore di ricerca. Qualcuno l'ha per caso letta e può mettere il link qui?
Non è una cosa così rara.
Se vai a vedere software e sistemi operativi per sonde e veicoli spaziali, centrali nucleari e roba di questo tipo, il coverage della verifica formale deve raggiungere spesso il 95% del codice. Esistono linguaggi appositi per la verifica formale. Cose che fero86 non conosce perché ha tolto ingegneria del software dal suo piano di studi :p
E' che c'era qualcosa di originale in quello che avevano raggiunto. Purtroppo vado a ricordi vaghi ma dichiaravano una cosa tipo "questo è il primo software che". Che poi lo facessero a ragion veduta o no non lo so perchè non ho più seguito la faccenda.
Sinceramente a me fa abbastanza schifo scrivere codice del tipo:
if(A)
if(B)
if(C)
if(D) ...
else errore D
else errore C
else errore B
else errore A
Dico, hai chiesto come scrivere in modo un po' piu' elegante 10 linee di codice e per risposta hai avuto paginate di codice poco chiaro e un sacco di seghe mentali... mah :D.
Come hai visto in queste tre pagine, le alternative sono altrettanto schifose :asd:, soprattutto se devi gestire l'errore in loco, perche' il codice per la gestione in un modo o nell'altro ce lo devi mettere.
Se invece l'errore devi solo ritornarlo allora ti conviene utilizzare uno qualsiasi dei metodi di short-circuit che ti sono stati proposti.
Se usi un linguaggio c-like la cosa piu' semplice secondo me e' una catena di && come forse ha gia' proposto qualcun altro.
return A() && B() && C() && D();
Rispetto ad altre soluzioni "ad oggetti", e mancando un sistema di macro serie in questi gruppi di linguaggi, e' l'unico metodo che ti permette anche di utilizzare funzioni con argomenti senza artifici strani.
Se il linguaggio inoltre permette l'allocazione sullo stack (e.g. C++) allora lo puoi sfruttare per la liberazione automatica delle risorse se necessario.
Una alternativa puo' essere quella di mettere le operazioni in una lista , ed eseguirla in ordine.
ops = [ A,B,C,D ]
for op in ops:
err = op()
if err:
return op
Pero' questo vale la pena solo se le operazioni sono parecchie e in ogni caso diventa scomodo passare argomenti diversi alle funzioni (dovresti creare funzioni che ritornano funzioni... e a quel punto tanto vale un po' di boilerplate in piu').
La gestione piu' carina probabilmente riesci a farla in haskell, dove utilizzando la struttura dati opportuna puoi semplicemente scrivere qualcosa tipo
foo :: String -> Either Error Result
foo filename
= do params <- getParameters filename
db <- connectToDb params
data <- selectFrom db
return $ Right extractInfoFrom data
e "automaticamente" l'esecuzione si ferma al primo errore.
In realta' con qualunque altro linguaggio funzionale serio puoi semplicemente creare una lista di funzioni valutate parzialmente e farla eseguire da una tua funzione custom 'sequence' che prenda un argomento iniziale e la sequenza di operazioni
foo filename =
let ops = [ getParameters,
connectToDb params,
selectFrom db,
extractInfoFrom data ]
in
sequence filename ops
Fuori i palteau ragazzi, è arrivato Armani.
Fuori i palteau ragazzi, è arrivato Armani.
Se per armani intendi Semplicita' ed concretezza ti ringrazio del complimento :p
Era per "l'eleganza"
...hai chiesto come scrivere in modo un po' piu' elegante...
Ma se me la fai spiegare non è più divertente!
leak-prone
leak per linguaggi vecchi che permettono i leak :p
senti, lascia proprio perdere che in questo forum ci sono un po' di persone che hanno visto in maniera molto diretta i risultati :asd:
Direi che non e' stato applicato fino in fondo.
Soprattutto occorrono persone che lo conoscono, e non che colgono l'occasione per impararlo.
da me si, a Ingegneria del Software, ma siccome ho scoperto che quel corso mi fa schifo l'ho tolto dal piano di studi :asd:
Non ho capito. In una ingegneria infomatica permettono di togliere dal piano di studi ingegneria del software?
leak per linguaggi vecchi che permettono i leak :p zitto tu e controlla che quella classe non implementi IDisposable :Prrr:
Direi che non e' stato applicato fino in fondo. peccato non poter piu controllare visto che a 'na certa il forum é stato spazzato via :asd: comunque, finché ho potuto lurkare, questo fek mi é sembrato piuttosto pignolo.
Soprattutto occorrono persone che lo conoscono, e non che colgono l'occasione per impararlo. e che so' scemi che ci mettono 4 anni ad impararlo? :rotfl:
Non ho capito. In una ingegneria infomatica permettono di togliere dal piano di studi ingegneria del software? in realtá, per fortuna, non si tratta di Ingegneria ma proprio di Informatica. da noi (la Sapienza) Ingegneria del Software non é uno di quei pochi corsi ritenuti indispensabili per il conseguimento della laurea specialistica, come lo sono invece Calcolabilitá e Complessitá, Architettura di Internet* e qualcun altro.
naturalmente non é che uno piglia e toglie le cose dal piano di studi: sempre un tot di crediti deve raggiungere, 120 nel caso del biennio della specialistica, quindi io ho sostituito le due Ingegnerie del Software (brrr) con altri due corsi che mi interessavano molto di piu e che ho scoperto dopo, per un totale di 12 crediti rimpiazzati. ma stai tranquillo che non ho preso assolutamente strade facili: ogni tanto mi chiedo se non sono stato troppo idiota a farmi un piano di studi cosi difficile (mi sono fatto guidare piu dall'interesse che dalla furbizia, cosa che non fa nessuno).
* nome bislacco per un corso che spiega lo stack TCP/IP piu altre cose accessorie.
Per quanto poco mi importi del tdd direi che diamonds abbia avuto dei problemi non correlati alla metodologia di sviluppo. A un certo punto son mancate le dita. Il che è piuttosto comune nei progetti non coatti. E' un peccato perchè a me piaceva vederlo andare avanti.
Per quanto poco mi importi del tdd direi che diamonds abbia avuto dei problemi non correlati alla metodologia di sviluppo. A un certo punto son mancate le dita. Il che è piuttosto comune nei progetti non coatti. E' un peccato perchè a me piaceva vederlo andare avanti. e il motivo per cui sono mancate le dita qual é? ricordo di aver letto dei post piuttosto eloquenti in merito!
zitto tu e controlla che quella classe non implementi IDisposable :Prrr:
E quindi? Pensi basti questo per un memory leak?
La maggior parte delle classi non implementa IDisposable
finché ho potuto lurkare, questo fek mi é sembrato piuttosto pignolo
Non lo metto in dubbio, infatti non penso proprio il problema fosse suo.
Sara' mancata costanza o voglia.
Era per "l'eleganza"
Ma se me la fai spiegare non è più divertente!
Lol, comunque ho una idea abbastanza pragmatica di eleganza quando parlo di codice
jappilas
21-03-2010, 11:40
peccato non poter piu controllare visto che a 'na certa il forum é stato spazzato via :asd:
peraltro con estremo dispiacere del sottoscritto (privato sia della sottosezione specifica del progetto, a lui affidata, sia di quanto poteva attestare uno dei punti più salienti del suo curriculum - e di quello di alcuni altri) :(
e che so' scemi che ci mettono 4 anni ad impararlo? :rotfl:
non confondere quello che adesso è su xp-dev.com con la sua sporadica (se non nulla) attività a tempo perso, con il progetto di HWUpgrade che nel 2006 impegnava una dozzina di persone a ritmo regolare per poi morire nel 2007 - quando la maggior parte dei membri del team iniziale ha cominciato a disertare
(compreso proprio il coach - fek passò in cruch time per B&W2 in quel periodo se non ricordo male)
jappilas
21-03-2010, 11:43
e il motivo per cui sono mancate le dita qual é? ricordo di aver letto dei post piuttosto eloquenti in merito!
a quel che ricordo, sporadiche build rotte e violazioni del checkstyle in primis :D impegni lavorativi in secundis...
peraltro con estremo dispiacere del sottoscritto (privato sia della sottosezione specifica del progetto, a lui affidata, sia di quanto poteva attestare uno dei punti più salienti del suo curriculum - e di quello di alcuni altri) :(
Le discussioni sono state tutte copiate nella sezione Programmazione.
Non è una cosa così rara.
Se vai a vedere software e sistemi operativi per sonde e veicoli spaziali, centrali nucleari e roba di questo tipo, il coverage della verifica formale deve raggiungere spesso il 95% del codice. Esistono linguaggi appositi per la verifica formale. Cose che fero86 non conosce perché ha tolto ingegneria del software dal suo piano di studi :p
Ciao,
potresti indicarmi qualche link in proposito? La cosa è molto interessante.
Ciao,
potresti indicarmi qualche link in proposito? La cosa è molto interessante.
Specifica formale, non verifica :D
Il già citato Linuguaggio Z (per l'esecuzione sequenziale), le reti di Petri/Petri estese (per la concorrenza), poi ci sono altri linguaggi specifici:
http://en.wikipedia.org/wiki/Specification_language
http://en.wikipedia.org/wiki/Petri_net (non ho trovato niente per quelle estese)
Un esempio di strumento per la verifica formale del codice (quantomeno per la parte procedurale) sono le triple di Hoare:
http://en.wikipedia.org/wiki/Hoare_logic
Specifica formale, non verifica :D
Il già citato Linuguaggio Z (per l'esecuzione sequenziale), le reti di Petri/Petri estese (per la concorrenza), poi ci sono altri linguaggi specifici:
http://en.wikipedia.org/wiki/Specification_language
http://en.wikipedia.org/wiki/Petri_net (non ho trovato niente per quelle estese)
Ma la specifica formale è fatta a livello algoritmico presumo. Cioè, riesco a dire se il mio algoritmo è matematicamente corretto. O si riesce a scovare anche errori di implementazione quali ad esempio memory leak per dirla alla C ? :D
Ma la specifica formale è fatta a livello algoritmico presumo. Cioè, riesco a dire se il mio algoritmo è matematicamente corretto. O si riesce a scovare anche errori di implementazione quali ad esempio memory leak per dirla alla C ? :D
Si', ci sono anche quelli. In generale pero' si fa solo la verifica di condizioni particolari (e.g. memory leak, dereferenziazione di null pointers e sforamento di array ). Al JPL ci sono uno o anche due gruppi che lavorano sull'argomento e hanno fatto parecchia ricerca a riguardo, e svilupppato dei tool per l'analisi tanto di Java quando di C++. Quello per java e' stato rilasciato open source e lo trovi qua: http://javapathfinder.sourceforge.net/
Per la verifica formale di piu' alto livello al momento ci si "accontenta" di farlo su modelli piu' astratti definito in un qualche linguaggio apposito. L'idea e' che specifichi come deve comportarsi il programma e poi fai l'analisi del modello. Il problema e' che da un lato scrivere correttamente le specifiche diventa difficile quasi quanto scrivere il programma, e il modello non riflette necessariamente il programma vero e proprio.
Comunque e' un campo di ricerca in piena attivita' per cui mi aspetto che le cose migliorino col tempo.
wingman87
21-03-2010, 13:26
Le discussioni sono state tutte copiate nella sezione Programmazione.
Temo che ormai sia tardi, ma non è che ci sia un modo per recuperare tutti i thread di Diamonds per raccoglierne i link in un unico thread?
Temo che ormai sia tardi, ma non è che ci sia un modo per recuperare tutti i thread di Diamonds per raccoglierne i link in un unico thread?
http://www.google.it/search?hl=it&safe=off&q=site:www.hwupgrade.it+%22Task+1%22&start=0&sa=N
http://www.google.it/search?hl=it&safe=off&q=site:www.hwupgrade.it+pair+programming&start=0&sa=N
tomminno
21-03-2010, 19:25
Non ho capito. In una ingegneria infomatica permettono di togliere dal piano di studi ingegneria del software?
Nell'indirizzo controlli numerici Ingegneria del Software non c'è. Altrimenti direi che è un esame obbligatorio.
wingman87
21-03-2010, 19:48
http://www.google.it/search?hl=it&safe=off&q=site:www.hwupgrade.it+%22Task+1%22&start=0&sa=N
http://www.google.it/search?hl=it&safe=off&q=site:www.hwupgrade.it+pair+programming&start=0&sa=N
Non ci avevo proprio pensato. Grazie!
e il motivo per cui sono mancate le dita qual é? ricordo di aver letto dei post piuttosto eloquenti in merito!
Probabilmente che non si campa, con i diamonds! :D Anche se, da esterno, sembrava una cosa molto bella.
Scusate l'intrusione, ogni tanto vi leggo, per vedere quanto sarebbe bello poter lavorare ancora nel campo....
LuVi
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.