Почему в C # есть как короткое замыкание ИЛИ, так и не замкнутая вариация этого оператора?

9

Периодически мне интересно об этом:

ИЛИ короткого замыкания всегда будет возвращать то же значение, что и оператор без короткого замыкания ИЛИ?

Я ожидаю, что короткое замыкание ИЛИ всегда будет оцениваться быстрее. Итак, был ли введен оператор без короткого замыкания ИЛИ в язык C # для согласованности?

Что я пропустил?

CarneyCode
источник
9
То же возвращаемое значение - да. Таких побочных эффектов - нет.
Работа
2
Пусть f()возбуждает исключение, рассмотрим true || f()и true | f(). Вы видите разницу? Первое выражение оценивает как true, а второе вычисляет исключение.
шарфридж

Ответы:

25

Оба операнда предназначались для разных вещей, происходящих из C, который не имеет логического типа. Версия с коротким замыканием || работает только с логическими значениями, а версия без короткого замыкания | работает с целочисленными типами, выполняя побитовое или. Просто так получилось, что это логическая операция без короткого замыкания для логических значений, которые представлены одним битом, равным 0 или 1.

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

Безопасный
источник
10
+1 за ссылку. Когда я прочитал этот вопрос, я был как "что?" поскольку afaik официальное название они являются логическими и побитовыми или, а не короткими замыканиями и короткими замыканиями, которые оказываются побочными эффектами их работы.
Стийн
1
+1 Я вижу, «работает только с булевыми операндами» - возможно, я не заметил разницы, потому что я все равно использую только выражения, которые оценивают как булевы значения
CarneyCode
2
Я должен был проверить, но на самом деле это правда, что |оператор при применении к двум логическим значениям компилируется в тот же orоператор в CIL, как и при применении к двум целочисленным значениям - в отличие от того, ||который компилируется в CIL с использованием brtrueдля условного Прыгать.
Квентин Старин
13

|(побитовое или) должно быть без короткого замыкания для таких типов, как int. Это потому, что почти во всех случаях вам нужно вычислить обе стороны |выражения, чтобы вычислить правильный результат. Например, что является результатом 7 | f(x)?

Если f(x)не оценивается, вы не можете сказать.

Кроме того, было бы непоследовательным вызывать короткое замыкание этого оператора bool, если оно не является коротким замыканием int. Между прочим, я думаю, что я никогда не использовал |намеренно логические сравнения, находя это очень неудобным, чтобы говорить |как логический оператор.

|| однако для логических сравнений, где оценка короткого замыкания работает нормально.

То же самое справедливо даже для C и C ++, где происхождение этих операторов.

Док Браун
источник
5

Это правильно, оператор ИЛИ короткого замыкания (||) всегда будет возвращать то же значение, что и оператор ИЛИ без короткого замыкания (|). (*)

Однако, если первый операнд является истинным, оператор короткого замыкания не будет вызывать оценку второго операнда, в то время как оператор без короткого замыкания всегда будет вызывать оценку обоих операндов. Это может повлиять на производительность, а иногда и на побочные эффекты.

Таким образом, есть смысл использовать и то и другое: если вы заботитесь о производительности, а оценка второго операнда не приводит к каким-либо побочным эффектам (или если вы не заботитесь о них), то непременно используйте оператор короткого замыкания. , Но если по какой-то причине вам нужны побочные эффекты второго операнда, вам следует использовать оператор без короткого замыкания.

Пример, где вы должны использовать оператор без короткого замыкания:

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

(*) За исключением некоторого действительно извращенного сценария, где оценка первого операнда ложными причинами побочным эффектом приводит к тому, что второй операнд оценивается как истинный вместо ложного.

Майк Накис
источник
2
+1 Но я хотел бы добавить, что помимо использования функций для обозначения успеха или неудачи (как в вашем примере): обычно следует избегать функций с побочными эффектами ...
Marjan Venema
1
Да, возможно, именно поэтому я никогда не использовал ни одного оператора без короткого замыкания до сегодняшнего дня, и шансы у меня малы, что я когда-либо буду.
Майк Накис
Этот пример зависит от того, какие операнды вычисляются в строгом порядке слева направо. C # гарантирует это, но многие схожие языки (включая C и C ++) этого не делают.
Кит Томпсон
Разве оценка короткого замыкания не имеет смысла для этого конкретного примера, поскольку все транзакции будут откатываться в случае сбоя какой-либо из них? (Я делаю некоторые предположения о семантике вызовов.)
Кит Томпсон
@KeithThompson вы правы, оценка без короткого замыкания вызовет ненужную обработку, и в этом смысле пример немного неубедительный, но он не настолько неубедителен, чтобы оправдывать изменение, потому что правда остается той, что при оценке короткого замыкания, если write_customer_to_database () завершается успешно, тогда остальные функции write _... никогда не будут вызываться, и в случае успеха лучше работать правильно, чем выполнять некоторые ненужные операции в случае сбоя.
Майк Накис
4

Было бы две причины использовать вариант без короткого замыкания:

  1. сохранение побочных эффектов (но это проще для кода с временной переменной)

  2. предотвратить атаки по времени , избегая разветвления в коротком замыкании (это может даже повысить эффективность времени выполнения, если второй операнд является переменной, но это микрооптимизация, которую компилятор может сделать в любом случае)

чокнутый урод
источник
Это единственная правильная причина, я не знаю, почему это не принятый ответ с наибольшим количеством голосов ...
Behrooz
2

если правое предложение оператора имеет побочный эффект, и программист предполагал, что он хочет, чтобы оба побочных эффекта произошли до проверки их возвращаемого значения.

Ли Райан
источник
5
Ик. Пожалуйста, не пишите так: если вы полагаетесь на побочные эффекты, имеете два разных выражения, присваиваете результаты и проверяете их впоследствии .
Конрад Рудольф