При написании программного кода на языке 1С:Предприятие 8 одной из самых частых задач является построение сложных условий с использованием операторов Если и Пока. Однако начинающие разработчики часто сталкиваются с ситуацией, когда, казалось бы, правильно составленное условие работает не так, как ожидалось. Разберем на конкретном примере, почему сочетание нескольких логических выражений может приводить к результату Ложь, и изучим фундаментальные правила работы логических операторов.
Проанализируем ситуацию, возникшую у автора темы. В коде было прописано следующее условие:
Если НЕ (Стр.СуммаОборотДт = 0 И Стр.СуммаОборотКт = 0) И (ТипЗнч(Стр.Период2) <> ТипЗнч(Неопределено)) Тогда
// Какая-то логика
КонецЕсли;
Автор поясняет, что первая часть выражения НЕ (Стр.СуммаОборотДт = 0 И Стр.СуммаОборотКт = 0) вычисляется как Ложь, а вторая часть (ТипЗнч(Стр.Период2) <> ТипЗнч(Неопределено)) — как Истина. Ошибка программиста заключалась в ожидании того, что общее выражение станет истинным. Однако в 1С, как и в классической математической логике, оператор И (конъюнкция) требует, чтобы все части выражения были истинными одновременно.
Выясним причину такого поведения, взглянув на классическую таблицу истинности для оператора И:
Таким образом, если хотя бы один из операндов, соединенных оператором И, равен Ложь, то и все выражение целиком будет равно Ложь.
Рассмотрим подробнее, в каком порядке система вычисляет выражения, если в одной строке кода их несколько. В языке 1С существует строгая иерархия (приоритет), которую важно учитывать, чтобы не запутаться в скобках:
НЕ Ложь становится Истиной.Если бы автор не использовал скобки в первой части своего условия, результат мог бы быть еще более непредсказуемым. Посмотрим на пример:
// Без скобок логика меняется:
Если НЕ Стр.СуммаОборотДт = 0 И Стр.СуммаОборотКт = 0 Тогда
В данном случае система сначала выполнит НЕ Стр.СуммаОборотДт = 0, а затем результат этой операции свяжет через И со вторым равенством. Использование скобок — это лучший способ явно указать платформе порядок вычислений и сделать код читаемым для других разработчиков.
Проанализируем важный нюанс платформы 1С:Предприятие 8, который часто игнорируют. В многих языках программирования (например, в JavaScript или C#) используется механизм "короткого замыкания" (short-circuiting): если в условии А И Б первая часть А оказалась Ложь, то вторая часть Б даже не будет проверяться, так как результат уже предрешен.
В языке 1С это работает не всегда одинаково. В некоторых контекстах (особенно в старых версиях платформы или специфических вызовах) система может попытаться вычислить оба выражения. Это критично, когда вторая часть условия зависит от первой. Рассмотрим опасный пример:
Если Объект <> Неопределено И Объект.Ссылка.Пустая() Тогда
// Если Объект все же Неопределено, этот код может вызвать ошибку
// "Обращение к процедуре объекта как к функции" или "Значение не является значением объектного типа"
КонецЕсли;
Чтобы гарантированно избежать ошибок, мы рекомендуем разделять такие проверки на вложенные условия Если:
Если Объект <> Неопределено Тогда
Если Объект.Ссылка.Пустая() Тогда
// Здесь мы в безопасности
КонецЕсли;
КонецЕсли;
Обратим внимание на вторую часть условия автора: ТипЗнч(Стр.Период2) <> ТипЗнч(Неопределено). С точки зрения производительности и стандартов разработки 1С, такая конструкция избыточна. Функция ТипЗнч() требует вычислительных ресурсов для определения типа и получения эталона.
Посмотрим, как можно упростить этот код. В 1С Неопределено — это и тип, и само значение одновременно. Поэтому прямое сравнение будет работать быстрее и выглядеть лаконичнее:
// Вместо: ТипЗнч(Стр.Период2) <> ТипЗнч(Неопределено)
// Пишем:
Стр.Период2 <> Неопределено
Результат будет идентичным, но код станет значительно чище.
Сложные конструкции с оператором НЕ и вложенными И/ИЛИ часто трудно читать. Для их упрощения программисты применяют законы де Моргана. Основное правило гласит: отрицание конъюнкции есть дизъюнкция отрицаний.
Разберем это на примере автора. У него было выражение:
НЕ (Стр.СуммаОборотДт = 0 И Стр.СуммаОборотКт = 0)
Применяя закон де Моргана, мы можем переписать его так:
(Стр.СуммаОборотДт <> 0) ИЛИ (Стр.СуммаОборотКт <> 0)
Согласитесь, второй вариант читается гораздо легче: "Если оборот по дебету не равен нулю или оборот по кредиту не равен нулю". Это избавляет от необходимости в уме "переворачивать" логику отрицания, что снижает риск возникновения ошибок при дальнейшей поддержке кода.
В обсуждении на форуме не упоминался тип NULL, однако при работе с данными из запросов он встречается постоянно. Важно помнить, что NULL — это не Ложь и не Истина, а "отсутствие значения".
В условиях Если любые операции, результатом которых является NULL, интерпретируются платформой как Ложь. Однако стоит помнить о нюансах:
НЕ NULL все равно остается NULL (а значит, в условии Если сработает как Ложь).ТипЗнч(Переменная) <> ТипЗнч(Неопределено), а в переменной находится NULL, условие вернет Истина, потому что тип NULL действительно не совпадает с типом Неопределено.Всегда проверяйте входящие данные на NULL с помощью функции ЗначениеЗаполнено() или явного сравнения, если данные получены из внешних источников или запросов с левым соединением.
Для успешной работы с логикой в 1С необходимо четко понимать три вещи: таблицу истинности, приоритеты операций и специфику типов данных. Чтобы ваши условия всегда работали корректно, старайтесь придерживаться следующих правил:
Неопределено используйте прямое сравнение Значение <> Неопределено.НЕ, используя законы де Моргана.И достаточно одного ложного значения, чтобы всё условие стало ложным.