Подтвердить что ты не робот

Почему язык НЕ использует оценку короткого замыкания?

Почему язык НЕ использует Оценка короткого замыкания? Существуют ли какие-либо выгоды от его использования?

Я вижу, что это может привести к некоторым проблемам с исполнением... это правда? Почему?


Связанный вопрос: Преимущества использования оценки короткого замыкания

4b9b3361

Ответ 1

Причины НЕ использовать оценку короткого замыкания:

  • Потому что он будет вести себя по-разному и даст разные результаты, если ваши функции, свойства Gets или методы оператора имеют побочные эффекты. И это может противоречить: A) языковым стандартам, B) предыдущим версиям вашего языка или C) предположениям по умолчанию для ваших типичных пользователей. Это причины, по которым VB не имеет короткого замыкания.

  • Поскольку вы можете пожелать, чтобы у complier была свобода, вы переупорядочиваете и обрезаете выражения, операторы и подвыражения по своему усмотрению, а не в том порядке, в котором пользователь их вводил. Вот причины, по которым SQL имеет для не короткого замыкания (или, по крайней мере, не так, как думает большинство разработчиков, приходящих на SQL). Таким образом, SQL (и некоторые другие языки) может быть короткозамкнутым, но только если он принимает решение и не обязательно в том порядке, который вы неявно указали.

Я предполагаю, что вы спрашиваете о "автоматическом, неявном порядке короткого замыкания", что большинство разработчиков ожидают от C, С++, С#, Java и т.д. Оба VB и SQL имеют способы явно принудительно короткое замыкание по заказу. Тем не менее, обычно, когда люди задают этот вопрос, это вопрос DWIM *, то есть они означают "почему он не делает то, что я хочу?", Как и в случае автоматического короткого замыкания в том порядке, в котором я его написал.

* - DWIM = "Do What я Meant"

Ответ 2

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

Пример:

if (true || someBooleanFunctionWithSideEffect()) {
    ...
}

Но это обычно нахмурилось.

Ответ 3

Ada не делает это по умолчанию. Чтобы усилить оценку короткого замыкания, вы должны использовать and then или or else вместо and или or.

Проблема в том, что есть некоторые обстоятельства, когда это фактически замедляет работу. Если второе условие быстро вычисляется, и первое условие почти всегда верно для "и" или "ложно" для "или", то дополнительная инструкция проверочной ветки является пустой тратой. Однако я понимаю, что с современными процессорами с отраслевыми предсказателями это не так. Другая проблема заключается в том, что компилятор может знать, что вторая половина дешевле или, скорее всего, терпит неудачу, и может захотеть соответствующим образом изменить порядок проверки (что не может быть выполнено, если определено поведение короткого замыкания).

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

В случае, если вас интересует, что должны сказать фактические разработчики языка об этой проблеме, здесь выдержка из Ada 83 (исходный язык) Обоснование:

Операнды булевого выражения такие как A и B, могут быть оценены в Любой заказ. В зависимости от сложности от термина B, это может быть больше эффективный (для некоторых, но не для всех машины) для оценки B только тогда, когда термин A имеет значение TRUE. Эта однако это решение по оптимизации взятый компилятором, и это будет неверно предположить, что это оптимизация всегда выполняется. В других ситуациях, которые мы можем захотеть выразить соединение условий, в которых каждый условие должно быть оценено ( значение), только если предыдущий условие выполнено. Оба из них все может быть сделано с коротким замыканием формы управления...

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

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

Ответ 4

Посмотрите на мой пример в В коротком замыкании оператора bullean оператора SQL, который показывает, почему определенный путь доступа в SQL более эффективен, если boolean короткое замыкание не. Пример моего блога показывает, как на самом деле полагаться на логическое короткое замыкание может сломать ваш код, если вы предполагаете короткое замыкание в SQL, но если вы читаете рассуждения, почему сначала оценивает правую сторону SQL, вы увидите, что это правильно и это приводит к значительно улучшенному пути доступа.

Ответ 5

Я бы сказал, что 99 раз из 100 я бы предпочел операторы короткого замыкания для производительности.

Но есть две большие причины, которые я нашел там, где я их не буду использовать. (Кстати, мои примеры находятся на C, где && и || закорачиваются, а и и | не являются.)

1.) Если вы хотите вызывать две или более функции в выражении if независимо от значения, возвращаемого первым.

if (isABC() || isXYZ()) // short-circuiting logical operator
    //do stuff;

В этом случае isXYZ() вызывается только если isABC() возвращает false. Но вы можете хотеть, чтобы isXYZ() вызывался независимо от того, что.

Итак, вы делаете это:

if (isABC() | isXYZ()) // non-short-circuiting bitwise operator
    //do stuff;

2.) Когда вы выполняете логическую математику с целыми числами.

myNumber = i && 8; // short-circuiting logical operator

не обязательно совпадает с:

myNumber = i & 8; // non-short-circuiting bitwise operator

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

Как я и намекал, эти два сценария действительно редки для меня. Но вы можете видеть, что существуют реальные причины программирования для обоих типов операторов. И, к счастью, большинство популярных языков сегодня имеют и то, и другое. Даже у VB.NET есть операторы короткого замыкания AndAlso и OrElse. Если на современном языке у меня нет обоих, я бы сказал это за раз и действительно ограничил программиста.

Ответ 6

Билл ссылается на действительную причину, чтобы не использовать короткое замыкание, а для более подробного написания: высокопараллельные архитектуры иногда имеют проблемы с ветвями управления ветвями.

Возьмите, например, архитектуру CUDA NVIDIA. Графические чипы используют архитектуру SIMT, что означает, что один и тот же код выполняется во многих параллельных потоках. Однако это работает только в том случае, если все потоки принимают одну и ту же условную ветвь каждый раз. Если разные потоки принимают разные кодовые пути, оценка сериализуется - это означает, что преимущество распараллеливания теряется, потому что некоторые из потоков должны ждать, пока другие выполняют альтернативную ветвь кода.

Короткое замыкание на самом деле предполагает разветвление кода, поэтому операции короткого замыкания могут быть вредными для архитектур SIMT, таких как CUDA.

- Но, как сказал Билл, это аппаратное соображение. Что касается языков, Id отвечает на ваш вопрос громким no: предотвращение короткого замыкания не имеет смысла.

Ответ 7

Если вы хотите оценить правую сторону:

if( x < 13 | ++y > 10 )
    printf("do something\n");

Возможно, вы хотели, чтобы у увеличивалось или не было x < 13. Хорошим аргументом против этого, однако, является то, что создание условий без побочных эффектов обычно является лучшей практикой программирования.

Ответ 8

Как растяжка:

Если вы хотите, чтобы язык был супер безопасным (ценой удивительности), вы бы устранили короткое замыкание. Когда что-то "безопасное" занимает переменное время, можно использовать Timing Attack. Короткое замыкание eval приводит к тому, что вещи принимают разные времена для выполнения, следовательно, вырывая дыру для атаки. В этом случае, даже не позволяя короткое замыкание eval, мы надеемся, поможет написать более безопасные алгоритмы (в любом случае, портить время).

Ответ 9

Язык Ada поддерживает как логические операторы, не имеющие короткого замыкания (AND, OR), чтобы разрешить компилятор для оптимизации и, возможно, распараллеливания конструкций и операторов с явным запросом на короткое замыкание (AND THEN, OR ELSE), когда это желает программист. Недостатком такого двойного подхода является сделать язык немного сложнее (1000 дизайнерских решений, принятых в одной и той же версии "let do both!", Сделает язык программирования более сложным в целом; -).

Ответ 10

Язык Luster не использует оценку короткого замыкания. В if-then-elses, как ветки then, так и else вычисляются при каждом тике, и один считается результатом условного в зависимости от оценки условия.

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

В Lustre, записывая эквивалент

if (y <> 0) then 100/y else 100

- типичная ошибка начинающего. Деление на ноль не исключается, поскольку выражение 100/y оценивается даже в циклах, когда y = 0.

Ответ 11

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

Эти родственники важны для высокопараллельных процессоров, которые имеют тенденцию оценивать несколько ветвей и выбирать один.

Эй, это немного растягивается, но вы спросили: "Зачем нужен язык"... нет "Почему язык".

Ответ 12

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

if(!SomeMethodThatChangesState() || !SomeOtherMethodThatChangesState())

Ответ 13

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

Если память используется, erlang предоставляет две конструкции, стандартные и/или, затем andalso/orelse. Это поясняет, что "да, я знаю, что это короткое замыкание, и вы тоже должны", где, как и в других случаях, цель должна быть получена из кода.

В качестве примера скажем, что сопровождающий сталкивается с этими строками:

if(user.inDatabase() || user.insertInDatabase()) 
    user.DoCoolStuff();

Требуется несколько секунд, чтобы понять, что целью является "если пользователь не находится в базе данных, вставьте его/ее/ее, если это работает, делайте классные вещи".

Как отмечали другие, это действительно актуально только при выполнении действий с побочными эффектами.

Ответ 14

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

Ответ 15

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

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

  • Код находится во внутреннем цикле, который очень часто называется
  • Существует высокая стоимость, связанная с оценкой выражений (возможно, IO или дорогостоящим вычислением)

Ответ 16

Оценка короткого замыкания автоматически обеспечивает условную оценку части выражения.

Основное преимущество заключается в том, что оно упрощает выражение.

Производительность может быть улучшена, но вы также можете наблюдать штраф за очень простые выражения.

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

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

Ответ 17

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

Это всего лишь одна из вещей, из-за которой мне было очень сложно выбраться из программиста, который писал код спагетти, и продолжить свое путешествие, чтобы стать настоящим программистом.

Ответ 18

Многие ответы говорили о побочных эффектах. Здесь пример Python без побочных эффектов, в которых (на мой взгляд) короткое замыкание улучшает читаемость.

for i in range(len(myarray)):
  if myarray[i]>5 or (i>0 and myarray[i-1]>5):
    print "At index",i,"either arr[i] or arr[i-1] is big"

Короткое замыкание гарантирует, что мы не пытаемся получить доступ к myarray [-1], что вызовет исключение, так как массивы Python начинаются с нуля. Конечно, код может быть записан без коротких замыканий, например.

for i in range(len(myarray)):
  if myarray[i]<=5: continue
  if i==0: continue
  if myarray[i-1]<=5: continue
  print "At index",i,...

но я думаю, что версия короткого замыкания более читаема.