Оценка короткого замыкания - Short-circuit evaluation
Эта статья нужны дополнительные цитаты для проверка. (август 2013) (Узнайте, как и когда удалить этот шаблон сообщения) |
Было высказано предположение, что Оператор Элвиса быть слился в эту статью. (Обсуждать) Предлагается с ноября 2020 года. |
| Стратегии оценки |
|---|
Оценка короткого замыкания, минимальная оценка, или же Оценка Маккарти (после Джон Маккарти ) является семантикой некоторых Логические операторы в некоторых языки программирования в котором второй аргумент выполняется или оценивается, только если первого аргумента недостаточно для определения значения выражения: когда первый аргумент И функция оценивается как ложный, общее значение должно быть ложный; и когда первый аргумент ИЛИ ЖЕ функция оценивается как истинный, общее значение должно быть истинный.
В языках программирования с ленивая оценка (Лисп, Perl, Haskell ) обычные логические операторы являются короткозамкнутыми. В других (Ада, Ява, Delphi ) доступны как короткие замыкания, так и стандартные логические операторы. Для некоторых логических операций, например Эксклюзивный или (XOR) короткое замыкание невозможно, поскольку для определения результата всегда требуются оба операнда.
Операторы короткого замыкания, по сути, управляющие структуры а не простые арифметические операторы, поскольку они не строгий. В повелительный язык условия (особенно C и C ++ ), где важны побочные эффекты, операторы короткого замыкания вводят точка последовательности - полностью оценивают первый аргумент, включая любые побочные эффекты, перед (необязательно) обработкой второго аргумента. АЛГОЛ 68 использовал производство достигать определяемые пользователем операторы и процедуры короткого замыкания.
Использование операторов короткого замыкания критиковалось как проблематичное:
Условные связки - "Cand" и "кор"для краткости - ... менее невинны, чем могут показаться на первый взгляд. Например, кор не распространяется Cand: сравнивать
- (А Cand Б) кор C с (А кор C) Cand (B кор C);
в случае ¬A ∧ C второе выражение требует, чтобы B был определен, а первое - нет. Поскольку условные связки усложняют формальные рассуждения о программах, их лучше избегать.
Определение
На любом языке программирования, реализующем оценку короткого замыкания, выражение Икс и у эквивалентен условное выражение если Икс тогда у еще Икс, а выражение Икс или же у эквивалентно если Икс тогда Икс еще у. В любом случае, Икс оценивается только один раз.
Обобщенное определение, приведенное выше, подходит для языков со слабой типизацией, которые имеют более двух истинные ценности Истинный и Ложь, где операторы короткого замыкания могут возвращать последнее вычисленное подвыражение. В приведенной ниже таблице это называется «последним значением». Для строго типизированного языка выражение упрощается до если Икс тогда у еще ложный и если Икс тогда истинный еще у соответственно для логического случая.
Приоритет
Несмотря на то что И берет приоритет над ИЛИ ЖЕ во многих языках это не универсальное свойство оценки короткого замыкания. Пример того, как два оператора имеют одинаковый приоритет и являются левоассоциативный друг с другом Оболочка POSIX синтаксис списка команд.[2](§2.9.3)
Следующий простой вычислитель с написанием слева направо обеспечивает приоритет И над ИЛИ ЖЕ по Продолжить:
функция короткое замыкание-eval (операторы, значения) позволять результат : = Верно для каждого (op, вал) в (операторы, значения): если op = "И" && результат = Ложь Продолжить иначе если op = "ИЛИ" && результат = Верно возвращаться результат еще результат := вал возвращаться результат
Формализация
Логика короткого замыкания с побочными эффектами или без них была формализована на основе Условное. В результате операторы без короткого замыкания могут быть определены из логики короткого замыкания, чтобы иметь ту же последовательность оценки.[3]
Поддержка распространенных языков программирования и сценариев
| Язык | Жаждущий операторы | Операторы короткого замыкания | Тип результата |
|---|---|---|---|
| Расширенное программирование бизнес-приложений (ABAP ) | никто | и, или же | Булево1 |
| Ада | и, или же | а потом, или иначе | Булево |
| АЛГОЛ 68 | и, &, ∧; или, ∨ | andf, orf (оба определены пользователем) | Булево |
| APL | ∧, ∨, ⍲ (нанд), ⍱ (ни) и т. д. | :И если, :Или если | Булево1 |
| awk | никто | &&, || | Булево |
| Баш | никто | &&, || | Булево |
| C, Цель-C | никто | &&, ||, ?[4] | int (&&,||), зависимо от opnd (?) |
| C ++2 | никто | &&, ||, ?[5] | Логическое (&&,||), зависимо от opnd (?) |
| C # | &, | | &&, ||, ?, ?? | Логическое (&&,||), зависимо от opnd (?, ??) |
| Язык разметки ColdFusion (CFML) | никто | И, ИЛИ ЖЕ, &&, || | Булево |
| D3 | &, | | &&, ||, ? | Логическое (&&,||), зависимо от opnd (?) |
| Эйфель | и, или же | а потом, или иначе | Булево |
| Erlang | и, или же | а также, Орлсе | Булево |
| Фортран4 | .и., .или же. | .и., .или же. | Булево |
| Идти, Haskell, OCaml | никто | &&, || | Булево |
| Ява, MATLAB, р, Быстрый | &, | | &&, || | Булево |
| JavaScript, Юля | &, | | &&, || | Последнее значение |
| Лассо | никто | и, или же, &&, || | Последнее значение |
| Котлин | и, или же | &&, || | Булево |
| Лисп, Lua, Схема | никто | и, или же | Последнее значение |
| МАМПЫ (М) | &, ! | никто | Числовой |
| Модула-2 | никто | И, ИЛИ ЖЕ | Булево |
| Оберон | никто | &, ИЛИ ЖЕ | Булево |
| OCaml | никто | &&, || | Булево |
| Паскаль | и, или же5,9 | а потом, or_else6,9 | Булево |
| Perl | &, | | &&, и, ||, или же | Последнее значение |
| Рубин | и, или же | &&, || | Последнее значение |
| PHP | &, | | &&, и, ||, или же | Булево |
| Оболочка POSIX (список команд) | никто | &&, || | Последнее значение (выход) |
| Python | никто[6] | и, или же | Последнее значение |
| Ржавчина | &, | | &&, ||[7] | Булево |
| Болтовня | &, | | и:, или же:7 | Булево |
| Стандартный ML | Неизвестно | а также, Орлсе | Булево |
| TTCN-3 | никто | и, или же[8] | Булево |
| Visual Basic .NET | И, Или же | А также, OrElse | Булево |
| Visual Basic, Visual Basic для приложений (VBA) | И, Или же | Выбрать дело8 | Числовой |
| Язык Wolfram Language | И @@ {...}, Или же @@ {...} | И, Или же, &&, || | Булево |
| ZTT | &, | | никто | Булево |
1 ABAP и APL не имеют отдельного логического типа.
2 При перегрузке операторы && и || нетерпеливы и могут вернуть любой тип.
3 Это применимо только к выражениям, оцениваемым во время выполнения, статический, если и статическое утверждение. Выражения в статических инициализаторах или константах манифеста используют активное вычисление.
4 Операторы Fortran не являются ни коротким замыканием, ни стремлением: спецификация языка позволяет компилятору выбрать метод для оптимизации.
5 ISO / IEC 10206: 1990 Расширенный Паскаль допускает, но не требует короткого замыкания.
6 ISO / IEC 10206: 1990 Extended Pascal поддерживает а потом и or_else.[9]
7 Smalltalk использует семантику короткого замыкания до тех пор, пока аргумент и: блок (например, false и: [Расшифровка стенограммы: "Не увидишь меня"]).
8 БАЗОВЫЙ языки, поддерживающие операторы CASE, сделали это с помощью системы условной оценки, а не в виде таблиц переходов, ограниченных фиксированными метками.
9 Delphi и Free Pascal по умолчанию оценка короткого замыкания. Это может быть изменено параметрами компилятора, но, похоже, не используется широко.
Общего пользования
Избегайте нежелательных побочных эффектов второго аргумента
Обычный пример с использованием На основе C язык:
int деноминация = 0;если (деноминация != 0 && число / деноминация){ ... // гарантирует, что вычисление num / denom никогда не приведет к ошибке деления на ноль }Рассмотрим следующий пример:
int а = 0;если (а != 0 && myfunc(б)){ сделай что-нибудь();}В этом примере оценка короткого замыкания гарантирует, что myfunc (б) никогда не называется. Это потому что а! = 0 оценивает ложный. Эта функция позволяет использовать две полезные программные конструкции.
- Если первое подвыражение проверяет, необходимы ли дорогостоящие вычисления, и проверка дает результат ложный, можно исключить дорогостоящие вычисления во втором аргументе.
- Это разрешает конструкцию, в которой первое выражение гарантирует условие, без которого второе выражение может вызвать ошибка выполнения.
Оба показаны в следующем фрагменте кода C, где минимальная оценка предотвращает как разыменование нулевого указателя, так и выборку излишней памяти:
bool is_first_char_valid_alpha_unsafe(const char *п){ возвращаться isalpha(п[0]); // SEGFAULT очень возможно с p == NULL}bool is_first_char_valid_alpha(const char *п){ возвращаться п != НОЛЬ && isalpha(п[0]); // 1) нет ненужного выполнения isalpha () с p == NULL, 2) нет риска SEGFAULT}Идиоматическая условная конструкция
Поскольку минимальная оценка является частью семантического определения оператора, а не (необязательной) оптимизацией, многие шаблоны кодирования[который? ] стали полагаться на него как на краткую (если идиоматическую) условную конструкцию. Примеры включают:
Perl идиомы:
some_condition или же умереть; # Прервать выполнение, если some_condition ложноsome_condition и умереть; # Прервать выполнение, если some_condition истинноОболочка POSIX идиомы:[10]
modprobe -q some_module && эхо "some_module установлен" || эхо "some_module не установлен"Эта идиома предполагает, что эхо не может потерпеть неудачу.
Возможные проблемы
Непроверенное второе условие приводит к невыполненным побочным эффектам
Несмотря на эти преимущества, минимальная оценка может вызвать проблемы для программистов, которые не осознают (или забывают), что это происходит. Например, в коде
если (выражениеA && myfunc(б)) { сделай что-нибудь();}если myfunc (б) должен выполнить некоторую требуемую операцию независимо от того, сделай что-нибудь() выполняется, например, распределение системных ресурсов, и выражениеA оценивается как ложь, тогда myfunc (б) не будет выполняться, что может вызвать проблемы. Некоторые языки программирования, такие как Ява, имеют два оператора, один из которых использует минимальную оценку, а другой нет, чтобы избежать этой проблемы.
Проблемы с невыполненными операторами побочных эффектов можно легко решить с помощью правильного стиля программирования, т. Е. Без использования побочных эффектов в логических операторах, поскольку использование значений с побочными эффектами в оценках обычно делает код непрозрачным и подверженным ошибкам.[11]
Снижение эффективности из-за ограничивающих оптимизаций
Короткое замыкание может привести к ошибкам в предсказание ветвления на современном центральные процессоры (ЦП) и резко снизят производительность. Ярким примером является высокооптимизированный луч с выровненным по оси кодом пересечения прямоугольника в трассировка лучей.[требуется разъяснение ] Некоторые компиляторы могут обнаруживать такие случаи и генерировать более быстрый код, но семантика языка программирования может ограничивать такую оптимизацию.[нужна цитата ]
Примером компилятора, который не может оптимизировать для такого случая, является Ява Hotspot VM по состоянию на 2012 год.[12]
Смотрите также
Рекомендации
- ^ Эдсгер В. Дейкстра «О несколько неутешительной переписке», EWD1009-0, 25 мая 1987 г. полный текст
- ^ "Командный язык оболочки". pubs.opengroup.org.
- ^ Ян А. Бергстра, А. Понс, D.J.C. Штаудт (2010). «Логика короткого замыкания». arXiv:1010.3674 [cs.LO ].CS1 maint: использует параметр авторов (связь)
- ^ Стандарт ISO / IEC 9899, раздел 6.5.13
- ^ Проект ISO / IEC IS 14882.
- ^ https://wiki.python.org/moin/BitwiseOperators
- ^ "std :: ops - Ржавчина". doc.rust-lang.org. Получено 2019-02-12.
- ^ ETSI ES 201 873-1 V4.10.1, раздел 7.1.4
- ^ "and_then - Руководство по GNU Pascal". Gnu-pascal.de. Получено 2013-08-24.
- ^ "Что означает || в bash?". stackexchange.com. Получено 2019-01-09.
- ^ «Ссылочная прозрачность, определенность и несгибаемость» (PDF). Itu.dk. Получено 2013-08-24.
- ^ Вассерман, Луи. "java - В каких случаях лучше использовать безусловное И (& вместо &&)". Переполнение стека.