Изменяет ли объединение сокращающих операторов с регулярными операторами результат выражения?

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

var result = true | false & false;

имеет тот же результат, что и

var result = true || false && false

Оба выражения приводят к true.

Но что, если бы я смешал обычные и условные операторы?

var result1 = true || false & false;
var result2 = true | false && false;

Чего бы вы ожидали? Я ожидал, что они все равно вернут true. Но это не так. Результат2 будет false!

Я знаю, что это из-за приоритета оператора < / а>. Порядок приоритета - & | && ||. Мне это кажется нелогичным. Я бы ожидал порядка & && | ||, и в этом случае все результаты будут одинаковыми (я думаю).

Так что я полагаю, что мой настоящий вопрос не в том, может ли короткое замыкание изменить результат. Возникает вопрос, почему порядок приоритета таков, что короткое замыкание может изменить результат.


person comecme    schedule 03.02.2013    source источник
comment
Короткое замыкание определенно может изменить побочные эффекты (то есть, если логические выражения являются методами), и поэтому имеет смысл проводить различия.   -  person antonijn    schedule 03.02.2013
comment
@Antonijn: вы имеете в виду, что это может изменить побочные эффекты?   -  person comecme    schedule 03.02.2013
comment
Простите, я должен был быть яснее.   -  person antonijn    schedule 03.02.2013
comment
Ответ скучный, потому что он унаследовал правила приоритета и ассоциативности от C, как и все языки с фигурными скобками. Сделайте его интересным, играя роль разработчика языка и предложите альтернативу. У вас есть только несколько вариантов, приоритет может быть противоположным или равным. Если равно, то имеет значение ассоциативность, возможно, то, что вы упустили.   -  person Hans Passant    schedule 03.02.2013


Ответы (3)


var result2 = true | false && false;

Рассчитывается как:

var result2 = (true | false) && false;

Потому что | предшествует &&. Теперь (true | false) оценивается как true, а true && false ложно.

Что касается почему, см. этот вопрос:

&& и || операторы были добавлены позже из-за их поведения "короткого замыкания". Деннис Ричи ретроспективно признает, что приоритет побитовых операторов должен был быть изменен при добавлении логических операторов. Но с учетом того, что на тот момент существовало несколько сотен килобайт исходного кода C и установленная база из трех компьютеров, Деннис подумал, что это будет слишком большим изменением в языке C ...

person CodeCaster    schedule 03.02.2013
comment
Насколько мне известно, & и | Операторы предназначены для побитовых операций, это не то, что вы можете использовать в своем первом предложении, обычные логические операторы. Поскольку bool может представлять один бит, он работает и для них. && и || операторы - это логические операторы для значений истинности. - person Dirk; 03.02.2013
comment
Несомненно, разработчики C # просто скопировали приоритет, уже известный из C и C ++. Но обратите внимание, что поток, на который вы ссылаетесь, призывает переместить операторы & и | дальше от && и || с помощью операторов == и !=, так что сначала идут & и |, а затем идут == и !=, и только потом идут && и ||. Это было бы менее запутанно в C, потому что они используют один и тот же тип для целых и логических значений. Таким образом, когда они говорят if (i & j == 0), он компилируется нормально (не компилируется на C # с int), но определенно отличается от предполагаемого if ((i & j) == 0). - person Jeppe Stig Nielsen; 04.02.2013
comment
Я думаю, что это хорошая идея использовать & и | только тогда, когда мне нужно побитовое и / или. С этого момента для логических значений и / или я всегда буду использовать && и ||. - person comecme; 04.02.2013

Приоритет рассматриваемых операторов, по-видимому, напрямую копируется из приоритета в языке программирования C (и C ++).

Теперь в C они не используют разные типы для целых и логических чисел. Например, они могли написать:

if (i | j && x > 0)      // cf. the result2 of your question

и это должно означать, что «целые числа i и j побитовое or'ed дает что-то отличное от нуля И число x положительно». Таким образом, предполагается, что | и & в основном используются, когда операнды рассматриваются как целые числа (многобитовые числа), а || и && должны использоваться в основном, когда операнды рассматриваются как логические.

Так что в C может показаться естественным, что | связывает более строго, чем &&.

В C # у нас более высокая степень безопасности типов, и нет преобразований из Int32 в Boolean или из Boolean в Int32. Следовательно, больше невозможно «смешивать» вещи, и приоритет больше не кажется естественным.

Я предполагаю, что теоретически на C # можно было бы сделать оператор

public static bool operator |(bool b, bool c)

имеют другой приоритет, чем оператор

public static int operator |(int i, int j)

но от этого не станет лучше?

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

person Jeppe Stig Nielsen    schedule 03.02.2013

& И | Операторы оценивают оба аргумента (что может включать вызов метода), а затем возвращают результат операции and- или or-.

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

Например: true | SomeMethod() и false & SomeMethod() вызывают функцию SomeMethod () true || SomeMethod(), а false && SomeMethod() - нет.

true и false в этом примере, конечно, также могут быть переменными, я просто использовал константу, чтобы упростить понимание примера.

person Dirk    schedule 03.02.2013