Domanda

I creatori lingua Go scrivere :

  

Go non fornisce asserzioni. Sono indubbiamente conveniente, ma la nostra esperienza è stata che i programmatori li usano come una stampella per evitare di pensare a una corretta gestione degli errori e reporting. Una corretta gestione degli errori significa che i server continuano a funzionare dopo errori non fatali, invece di schiantarsi. Una corretta segnalazione di errore significa che gli errori sono diretti e al punto, salvando il programmatore di interpretare una grande traccia incidente. errori di precisione sono particolarmente importanti quando il programmatore di vedere gli errori non ha familiarità con il codice.

Qual è la tua opinione su questo?

È stato utile?

Soluzione

No, non c'è niente di sbagliato con assert finché lo si utilizza come previsto.

Cioè, si suppone che sia per la cattura di casi che "non può accadere", durante il debug, in contrapposizione alla normale gestione degli errori.

  • Assert: Un guasto nella logica del programma stesso
  • .
  • Gestione errori:. Un ingresso errato o lo stato del sistema non a causa di un bug nel programma

Altri suggerimenti

No, né gotoassert sono il male. Ma entrambi può essere utilizzato impropriamente.

Assert è per i controlli di integrità. Cose che dovrebbe uccidere il programma se non sono corrette. Non per la convalida o come un sostituto per la gestione degli errori.

Secondo questa logica, i punti di interruzione sono il male troppo.

afferma dovrebbe essere usato come un aiuto di debug, e nient'altro. "Male" è quando si tenta di utilizzarli al posto di gestione degli errori.

afferma sono lì per aiutarti, il programmatore, individuare e risolvere i problemi che non devono esistere e verificare che le ipotesi rimangono fedeli.

Non hanno nulla a che fare con la gestione degli errori, ma purtroppo, alcuni programmatori li abusano in quanto tale, e quindi dichiarare loro "male".

Mi piace usare assert molto. Trovo molto utile quando sto costruendo applicazioni per la prima volta (forse per un nuovo dominio). Invece di fare errori molto di fantasia di controllo (che vorrei prendere in considerazione l'ottimizzazione prematura) I codice veloce e aggiungo un sacco di afferma. Dopo Io so di più su come funzionano le cose che faccio una riscrittura e rimuovere alcuni dei asserisce e cambiarli per una migliore gestione degli errori.

A causa della asserisce Ho passato un sacco di meno programmi di codifica / debugging in tempo.

Ho anche notato che l'afferma aiutarmi a pensare di molte cose che potrebbero rompere i miei programmi.

Essi dovrebbero essere utilizzati per la rilevazione di bug nel programma. Non male l'input dell'utente.

Se usato correttamente, sono non il male.

Come ulteriori informazioni, visitare fornisce una funzione panic built-in. Questo può essere usato al posto di assert. Per es.

if x < 0 {
    panic("x is less than 0");
}

panic stamperà l'analisi dello stack, quindi in qualche modo ha lo scopo di assert.

Questo viene su molto, e penso che un problema che rende le difese di affermazioni confusione è che essi sono spesso basate su controllo argomento. Così considerare questo diverso esempio di quando si potrebbe utilizzare un'affermazione:

build-sorted-list-from-user-input(input)

    throw-exception-if-bad-input(input)

    ...

    //build list using algorithm that you expect to give a sorted list

    ...

    assert(is-sorted(list))

end

Si utilizza un'eccezione per l'ingresso in quanto ci si aspetta si otterrà brutta entrata volte. Lei asserisce che la lista è ordinata per aiutarvi a trovare un bug nel vostro algoritmo, che per definizione che non ti aspetti. L'affermazione è nella build di debug solo, quindi, anche se il controllo è costoso, non ti dispiace farlo su ogni singola chiamata di routine.

Hai ancora a unit-testare il vostro codice di produzione, ma questo è un diverso, e complementare, modo di fare che il codice è corretto. Prove di unità assicurarsi che la vostra routine vive fino alla sua interfaccia, mentre affermazioni sono un modo più dettagliato per assicurarsi che l'implementazione sta facendo esattamente quello che ci si aspetta a.

Le asserzioni non sono male, ma possono essere facilmente cattivo uso. Sono d'accordo con l'affermazione che "le asserzioni sono spesso usati come una stampella per evitare di pensare a una corretta gestione degli errori e reporting". Ho visto questo abbastanza spesso.

Personalmente, mi piace usare le asserzioni perché documentano assunzioni che avrei potuto fatte mentre a scrivere il mio codice. Se queste ipotesi sono rotti mantenendo il codice, il problema può essere rilevato durante la prova. Tuttavia, lo faccio fare il punto della escludendo ogni affermano dal mio codice quando si fa una build di produzione (vale a dire, usando #ifdefs). Mettendo a nudo le affermazioni nella build di produzione, elimino il rischio che qualcuno di loro abuso come una stampella.

C'è anche un altro problema con asserzioni. Le asserzioni vengono controllati solo in fase di esecuzione. Ma è spesso il caso che il controllo che si desidera eseguire avrebbe potuto essere eseguita a tempo di compilazione. È preferibile rilevare un problema in fase di compilazione. Per i programmatori C ++, boost fornisce BOOST_STATIC_ASSERT, che ti permette di fare questo. Per programmatori C, questo articolo ( link testuale ) descrive una tecnica che può essere utilizzata per eseguire asserzioni in fase di compilazione.

In sintesi, la regola del pollice seguo è: non utilizzare le asserzioni in una build di produzione e, se possibile, utilizzare solo asserzioni per le cose che non possono essere verificate al momento della compilazione (cioè, deve essere verificata in fase di esecuzione ).

Ammetto di aver usato asserisce mentre non considerando corretta la segnalazione degli errori. Tuttavia, ciò non toglie che essi sono molto utili se usati correttamente.

Sono particolarmente utili per se si vuole seguire il principio "Early Crash". Per esempio si supponga di attuazione di un meccanismo di conteggio di riferimento. In alcune località in vostro codice si sa che il refcount dovrebbe essere zero o uno. E anche supporre che se il refcount è sbagliato il programma non vada in crash immediatamente, ma nel corso del prossimo ciclo di messaggi a quel punto sarà difficile scoprire perché le cose andavano male. Un'asserzione sarebbe stato utile nel rilevare l'errore più vicino alla sua origine.

preferisco evitare codice che fa cose diverse in debug e di rilascio.

Rottura nel debugger su una condizione e avere tutte le informazioni del file / linea è utile, però, anche l'esatta espressione e il valore esatto.

Avere un'asserzione che "valutare la condizione solo in debug" può essere un'ottimizzazione delle prestazioni, e come tale, utile solo in 0,0001% dei programmi - in cui le persone sanno quello che stanno facendo. In tutti gli altri casi questo è dannoso, come l'espressione può effettivamente cambiare lo stato del programma:

assert(2 == ShroedingersCat.GetNumEars()); renderebbe il programma di fare cose diverse in debug e di rilascio.

Abbiamo sviluppato un insieme di macro assert che un'eccezione, e di farlo in entrambi i debug e rilasciare la versione. Per esempio, THROW_UNLESS_EQ(a, 20); sarebbe un'eccezione con il messaggio che cosa () avendo entrambi di file, la linea e le valori effettivi di una, e così via. Solo una macro avrebbe il potere per questo. Il debugger può essere configurato in modo da rompere al 'lancio' del tipo di eccezione specifica.

Cosa non mi piace afferma intensamente. Non vorrei andare per quanto riguarda dicendo che sono il male però.

In sostanza un'asserzione farà la stessa cosa come eccezione incontrollato sarebbe, l'unica eccezione è che l'assert (normalmente) non dovrebbe essere mantenuto per il prodotto finale.

Se si crea una rete di sicurezza per se stessi durante il debug e la costruzione del sistema perché si dovrebbe negare questa rete di sicurezza per il vostro cliente, o il vostro supporto help desk, o chiunque che otterrà di utilizzare il software che si sta costruendo. Utilizzare eccezioni esclusivamente per entrambi afferma e situazioni eccezionali. Con la creazione di una gerarchia di un'eccezione appropriata si sarà in grado di discernere molto rapidamente l'uno dall'altro. Ma questa volta l'asserzione rimane al suo posto e può fornire informazioni preziose in caso di guasto che altrimenti andrebbe persa.

Così ho capito pienamente i creatori di Go rimuovendo afferma del tutto e costringendo ai programmatori di utilizzare le eccezioni per gestire la situazione. C'è una spiegazione semplice per questo, ad eccezione sono solo un meccanismo migliore per il lavoro perché il bastone con l'arcaico afferma?

Risposta breve: No, credo che affermazioni possono essere utili

Recentemente ho iniziato l'aggiunta di qualche afferma al mio codice, e questo è il modo che ho fatto è:

I mentalmente divido il mio codice in codice di cinta e codice interno. Codice Boundary è il codice che gestisce l'input dell'utente, legge i file, e ottiene i dati dalla rete. In questo codice, chiedo di ingresso in un ciclo che esce solo quando l'ingresso è valido (nel caso di input dell'utente interattivo), o gettare eccezioni nel caso di dati corrotti irrecuperabile file / rete.

Codice interno è tutto il resto. Per esempio, una funzione che imposta una variabile nella mia classe potrebbe essere definito come

void Class::f (int value) {
    assert (value < end);
    member = value;
}

e una funzione che riceve input da una rete potrebbe leggere come tale:

void Class::g (InMessage & msg) {
    int const value = msg.read_int();
    if (value >= end)
        throw InvalidServerData();
    f (value);
}

Questo mi dà due strati di assegni. Tutto ciò in cui i dati è determinato a run-time ottiene sempre un'eccezione o la gestione degli errori immediato. Tuttavia, che il check-in più in Class::f con l'affermazione assert significa che se un certo codice interno mai chiama Class::f, ho ancora un controllo di integrità. Il mio codice interno potrebbe non passare un argomento valido (perché forse ho calcolato value da alcune complessa serie di funzioni), quindi mi piace avere l'affermazione nella funzione di impostazione per il documento che, indipendentemente da chi sta chiamando la funzione, value non deve essere superiore o uguale a end.

Questo sembra inserirsi in quello che sto leggendo in alcuni punti, che le affermazioni dovrebbero essere impossibile da violare in un programma ben funzionante, mentre eccezioni dovrebbero essere per casi eccezionali ed erronee che sono ancora possibili. Perché in teoria sto convalidando tutto l'input, non dovrebbe essere possibile per la mia affermazione di essere attivato. Se lo è, il mio programma è sbagliato.

assert è molto utile e può risparmiare un sacco di passi indietro quando si verificano errori imprevisti da arrestare il programma ai primi segni di difficoltà.

D'altra parte, è molto facile abusare assert.

int quotient(int a, int b){
    assert(b != 0);
    return a / b;
}

Il corretto, versione corretta sarebbe qualcosa di simile:

bool quotient(int a, int b, int &result){
    if(b == 0)
        return false;

    result = a / b;
    return true;
}

Quindi ... a lungo andare ... nella foto grande ... devo concordare può essere oggetto di abusi che assert. Io lo faccio tutto il tempo.

assert è abusato per la gestione degli errori, perché è meno di battitura.

Quindi, come progettisti di linguaggi, si dovrebbe piuttosto vedere che una corretta gestione degli errori può essere fatto con la digitazione anche minore. Escludendo affermare perché il meccanismo di eccezione è verbose non è la soluzione. Oh aspetta, Go non ha eccezioni sia. Peccato:)

Mi sono sentito come a calci l'autore nella testa quando ho visto che.

Io uso afferma tutto il tempo nel codice ed eventualmente sostituirli tutti quando scrivo più di codice. Li uso quando non ho scritto la logica necessaria e vogliono ricevere un avviso quando mi imbatto in codice invece di scrivere un'eccezione che sarà soppresso in quanto il progetto si avvicina al completamento.

Eccezioni anche fondono con codice di produzione più facilmente che non mi piace. Un'asserzione è più facile da notare che throw new Exception("Some generic msg or 'pretend i am an assert'");

Il mio problema con queste risposte difendere assert c'è nessuno specifica chiaramente che cosa lo rende diverso da un normale errore fatale , e perché un'asserzione non può essere un sottoinsieme di un eccezione . Ora, con questo detto, che cosa succede se l'eccezione viene mai catturato? Questo la rende un'affermazione nomenclatura? E, perché mai vogliono imporre una restrizione nella lingua che un'eccezione può essere sollevato che / niente / in grado di gestire?

Sì, asserisce sono il male.

Spesso si abituano in luoghi in cui deve essere utilizzata la corretta gestione degli errori. Abituatevi a scrivere una corretta gestione fin dall'inizio errore di qualità della produzione!

Di solito si ottengono nel modo di scrittura di unit test (a meno che non si scrive un assert personalizzato che interagisce con il tuo test harness). Questo è spesso perché essi sono utilizzati in cui deve essere utilizzata la corretta gestione degli errori.

Per lo più vengono compilate di release si basa il che significa che nessuno di loro "test" è disponibile quando si esegue il codice che in realtà rilascia; dato che in situazioni multi-threaded peggiori problemi spesso visualizzati solo nel codice di rilascio può essere male.

A volte sono una stampella per i disegni altrimenti rotti; cioè la progettazione del codice consente a un utente di richiamare in un modo che non dovrebbe essere chiamato e l'asserzione "impedisce" questo. Fissare il disegno!

Ho scritto di questo di più sul mio blog nel 2005 qui: http://www.lenholgate.com/blog/2005/09/assert-is-evil.html

Se il asserisce stai parlando significa che il programma vomita e poi esiste, affermazioni possono essere molto male. Questo non vuol dire che sono sempre la cosa sbagliata da usare, sono un costrutto che è molto facilmente abusato. Essi hanno anche molte alternative migliori. Cose del genere sono buoni candidati per essere chiamato il male.

Ad esempio, un modulo di 3a parte (o qualsiasi modulo realmente) dovrebbe quasi mai uscire dal programma chiamante. Questo non dà il programmatore di chiamare qualsiasi controllo su ciò che rischiare il programma dovrebbe prendere in quel momento. In molti casi, i dati è così importante che anche il salvataggio dei dati danneggiato è meglio che perdere i dati. Afferma può costringere a perdere i dati.

Alcune alternative a afferma:

  • Utilizzo di un debugger,
  • Console / database / altra logging
  • Eccezioni
  • Altri tipi di trattamento degli errori

Alcune referenze:

Anche le persone che sostengono assert pensano che dovrebbero essere utilizzati solo in fase di sviluppo e non nella produzione:

Questa persona dice che asserisce dovrebbe essere utilizzato quando il modulo è potenzialmente corrotto dati che persiste dopo viene generata un'eccezione: http://www.advogato.org/article/949.html . Questo è certamente un punto ragionevole, tuttavia, un modulo esterno deve non prescrivono quanto sia importante dati danneggiati è quello di programma chiamante (uscendo "per" loro). Il modo corretto per gestire questo è un'eccezione che chiarisce che il programma può ora essere in uno stato incoerente. E dal momento che i buoni programmi consistono per lo più di moduli (con un codice po 'di colla nel file eseguibile principale), afferma sono quasi sempre la cosa sbagliata da fare.

Non tanto male come generalmente controproducente. C'è una separazione tra il controllo degli errori permanente e il debugging. Assert fa pensare tutto il debug dovrebbe essere permanente e provoca problemi di leggibilità enormi quando viene utilizzato molto. errore permanente manipolazione dovrebbe essere migliore di quello dove necessario, e dal momento che assert provoca i propri errori è una pratica abbastanza discutibile.

Non ho mai utilizzare assert (), esempi di solito mostrano qualcosa di simile:

int* ptr = new int[10];
assert(ptr);

Questo è un male, non ho mai fare questo, che cosa succede se il mio gioco è l'allocazione di un gruppo di mostri? perché dovrei mandare in crash il gioco, invece si dovrebbe gestire gli errori con grazia, in modo da fare qualcosa di simile:

CMonster* ptrMonsters = new CMonster[10];
if(ptrMonsters == NULL) // or u could just write if(!ptrMonsters)
{
    // we failed allocating monsters. log the error e.g. "Failed spawning 10 monsters".
}
else
{
    // initialize monsters.
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top