Оценка короткого замыкания - 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_else 6,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 - В каких случаях лучше использовать безусловное И (& вместо &&)". Переполнение стека.