Perché c'è una variazione di cortocircuito O di cortocircuito o di cortocircuito di quell'operatore in C #?


9

Periodicamente, mi chiedo questo:

L'OR di cortocircuito restituirebbe sempre lo stesso valore dell'operatore OR non cortocircuitato?

Mi aspetto che il corto circuito O valuterà sempre più rapidamente. Quindi, l'operatore OR non cortocircuitato è stato incluso nel linguaggio C # per coerenza?

Cosa mi sono perso?


9
Stesso valore di ritorno - sì. Stessi effetti collaterali - no.
Giobbe

2
Supponiamo che f()sollevi un'eccezione, considera true || f()e true | f(). Vedi la differenza? La prima espressione valuta true, la valutazione di quest'ultima si traduce in un'eccezione generata.
scarfridge,

Risposte:


25

Entrambi gli operandi erano pensati per cose diverse, provenienti da C che non aveva un tipo booleano. La versione di corto circuito || funziona solo con i booleani, mentre la versione non in corto circuito | funziona con tipi integrali, eseguendo un bit per bit o. È capitato di funzionare come un'operazione logica non di corto circuito per i booleani che sono rappresentati da un singolo bit, essendo 0 o 1.

http://en.wikibooks.org/wiki/C_Sharp_Programming/Operators#Logical


10
+1 per il collegamento. Quando ho letto questa domanda ero come "cosa?" da allora il nome ufficiale di questi sono logici e bit per bit o, e non cortocircuito e corto circuito, che sono effetti collaterali del loro funzionamento.
stijn

1
+1 Vedo "opera solo su operandi booleani" - Probabilmente non ho notato la differenza perché utilizzo comunque solo espressioni che valutano booleane
Carney

2
Ho dovuto verificare, ma è vero che l' |operatore, quando applicato a due valori booleani, viene compilato nello stesso oroperatore in CIL come lo è quando viene applicato a due valori interi - a differenza di quello ||che viene compilato in CIL usando brtrueper un condizionale saltare.
Quentin-starin,

13

|(bitwise-or) deve essere non in cortocircuito per tipi come int. Questo perché in quasi tutti i casi è necessario calcolare entrambi i lati di |un'espressione per calcolare il risultato corretto. Ad esempio, qual è il risultato 7 | f(x)?

Se f(x)non viene valutato, non è possibile dirlo.

Inoltre, sarebbe incoerente mettere in corto circuito questo operatore boolquando non è in cortocircuito int. A proposito, penso di non aver mai usato |intenzionalmente confronti logici, trovando molto scomodo parlare di |operatore logico.

|| tuttavia è per confronti logici, in cui la valutazione del corto circuito funziona correttamente.

Lo stesso vale anche per C e C ++, dove si trova l'origine di tali operatori.


5

Ciò è corretto, l'operatore OR di corto circuito (||) restituirà sempre lo stesso valore dell'operatore OR di corto circuito (|). (*)

Tuttavia, se il primo operando è vero, l'operatore in cortocircuito non farà la valutazione del secondo operando, mentre l'operatore non in cortocircuito farà sempre la valutazione di entrambi gli operandi. Ciò può avere un impatto sulle prestazioni e talvolta sugli effetti collaterali.

Quindi, c'è un uso per entrambi: se ti preoccupi delle prestazioni e la valutazione del secondo operando non produce effetti collaterali (o se non ti importa di loro), allora usa l'operatore di cortocircuito . Ma se per qualche motivo hai bisogno degli effetti collaterali del secondo operando, allora dovresti usare l'operatore non in cortocircuito.

Un esempio in cui è necessario utilizzare l'operatore non in corto circuito:

if( write_customer_to_database() != SUCCESS |
    write_supplier_to_database() != SUCCESS |
    write_order_to_database() != SUCCESS )
{
    transaction_rollback();
}

(*) Ad eccezione di alcuni scenari realmente perversi in cui la valutazione del primo operando su false causa, per effetto collaterale, il secondo operando da valutare su true anziché su false.


2
+1 Ma vorrei aggiungere questo oltre a utilizzare le funzioni per indicare il successo o il fallimento (come nel tuo esempio): le funzioni con effetti collaterali dovrebbero essere generalmente evitate ...
Marjan Venema,

1
Sì, probabilmente è per questo che non ho mai usato nessuno degli operatori di corto circuito fino ad oggi, e le possibilità sono scarse che lo farò mai.
Mike Nakis,

Tale esempio dipende dagli operandi valutati in rigoroso ordine da sinistra a destra. C # lo garantisce, ma molti linguaggi simili (inclusi C e C ++) no.
Keith Thompson,

La valutazione del corto circuito non avrebbe senso per quel particolare esempio, dal momento che tutte le transazioni verranno annullate se una di esse fallisce? (Sto facendo alcune ipotesi sulla semantica delle chiamate.)
Keith Thompson,

@KeithThompson hai ragione, la valutazione senza cortocircuito causerà un'elaborazione non necessaria, e in questo senso l'esempio è un po 'zoppo, ma non è così zoppo da giustificare il cambiamento, perché la verità rimane che con la valutazione di corto circuito se write_customer_to_database () ha esito positivo, quindi il resto delle funzioni write _... non verrà mai chiamato ed è meglio operare correttamente in caso di successo, piuttosto che eseguire alcune operazioni non necessarie in caso di errore.
Mike Nakis,

4

Ci sarebbero 2 motivi per usare la variante senza cortocircuito:

  1. mantenendo gli effetti collaterali (ma è più chiaro codificare con una variabile temporanea)

  2. contrastare gli attacchi di temporizzazione evitando il fork nel cortocircuito (questo potrebbe persino migliorare l'efficienza di runtime se il secondo operando è una variabile ma che è comunque una micro-ottimizzazione che il compilatore può fare comunque)


Questa è l'unica ragione giusta fornita, non ho idea del perché questa non sia la risposta accettata con il massimo dei voti ...
Behrooz,

2

se la clausola di destra dell'operatore ha un effetto collaterale e il programmatore intendeva che voleva che si verificassero entrambi gli effetti collaterali prima di verificarne il valore di ritorno.


5
Eek. Per favore, non programmare così ... se fai affidamento su effetti collaterali, hai due espressioni diverse, assegna i risultati e testali in seguito .
Konrad Rudolph,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.