Как работает логическое условие без конструкции Если Тогда в 1С

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

В процессе анализа типовых конфигураций «1С:Предприятие» разработчики часто сталкиваются с конструкциями, которые на первый взгляд кажутся неполными или странными. Один из таких примеров — присваивание переменной или реквизиту значения, вычисляемого с помощью логических операторов И, ИЛИ, НЕ, без использования привычного условного оператора Если...Тогда...КонецЕсли.

В этой статье мы подробно разберем, как работают подобные конструкции, почему они активно применяются в типовых решениях (например, в «Управлении производственным предприятием» редакции 1.3), и в чем заключаются их преимущества с точки зрения производительности и стандартов разработки «1С».

Разбор исходного примера кода

Рассмотрим фрагмент кода, который вызвал вопросы. В модуле документа присутствует следующий метод:


Процедура УстановитьРеализацияТоваровОблагаемыхНДСУПокупателя()
    РеализацияТоваровОблагаемыхНДСУПокупателя = ДоговорКонтрагента.РеализацияТоваровОблагаемыхНДСУПокупателя 
        И ЭтотОбъект.Дата >= Константы.ДатаНачалаОперацийСТоварамиОблагаемымиНДСУПокупателя.Получить();
        
    СкрытьНДСПриРеализацияТоваровОблагаемыхНДСУПокупателя();
КонецПроцедуры

У начинающих разработчиков возникает резонный вопрос: почему здесь нет конструкции Если...Тогда? Как система понимает, что нужно делать, и почему этот код работает?

Давайте проанализируем выражение детально. Здесь происходит операция присваивания реквизиту документа РеализацияТоваровОблагаемыхНДСУПокупателя (который имеет тип Булево) результата вычисления логического выражения. В правой части оператора равенства (=) находится сложное логическое условие, состоящее из двух частей, соединенных оператором И:

  1. Значение реквизита договора контрагента: ДоговорКонтрагента.РеализацияТоваровОблагаемыхНДСУПокупателя (тип Булево).
  2. Результат сравнения даты документа с константой: ЭтотОбъект.Дата >= Константы.ДатаНачалаОперацийСТоварамиОблагаемымиНДСУПокупателя.Получить() (результат сравнения дат всегда возвращает тип Булево — либо Истина, либо Ложь).

Платформа сначала вычисляет общее логическое значение выражения в правой части, а затем записывает полученный результат (Истина или Ложь) в реквизит, расположенный слева от знака равенства.

Принцип прямого булевого присваивания (избавление от избыточности)

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

Избыточный (нерекомендуемый) вариант с использованием условного оператора:


Если ДоговорКонтрагента.РеализацияТоваровОблагаемыхНДСУПокупателя = Истина 
   И ЭтотОбъект.Дата >= Константы.ДатаНачалаОперацийСТоварамиОблагаемымиНДСУПокупателя.Получить() Тогда
    РеализацияТоваровОблагаемыхНДСУПокупателя = Истина;
Иначе
    РеализацияТоваровОблагаемыхНДСУПокупателя = Ложь;
КонецЕсли;

Лаконичный (правильный) вариант с прямым присваиванием:


РеализацияТоваровОблагаемыхНДСУПокупателя = ДоговорКонтрагента.РеализацияТоваровОблагаемыхНДСУПокупателя 
    И ЭтотОбъект.Дата >= Константы.ДатаНачалаОперацийСТоварамиОблагаемымиНДСУПокупателя.Получить();

Оба варианта выполняют абсолютно одинаковую задачу. Однако первый вариант содержит избыточные конструкции ветвления. В стандартах разработки фирмы «1С» строго указано, что избыточных проверок и явных присвоений булевых литералов (Истина и Ложь) в условных операторах следует избегать. Прямое присваивание делает код чище, проще для чтения и поддержки.

Механизм «ленивых» вычислений в платформе 1С:Предприятие

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

Платформа «1С:Предприятие» вычисляет логические выражения слева направо. Как только конечный результат выражения становится очевидным, вычисление оставшейся части прекращается:

Посмотрим, как это работает на нашем примере:


РеализацияТоваровОблагаемыхНДСУПокупателя = ДоговорКонтрагента.РеализацияТоваровОблагаемыхНДСУПокупателя 
    И ЭтотОбъект.Дата >= Константы.ДатаНачалаОперацийСТоварамиОблагаемымиНДСУПокупателя.Получить();

Если у выбранного договора контрагента флаг РеализацияТоваровОблагаемыхНДСУПокупателя установлен в значение Ложь, то платформа вообще не будет обращаться к базе данных для чтения константы ДатаНачалаОперацийСТоварамиОблагаемымиНДСУПокупателя! Вычисление прекратится на первом операнде, и переменной сразу присвоится значение Ложь.

Если бы мы написали сложную структуру с предварительным получением данных из констант или функций, система совершала бы лишние, дорогостоящие операции чтения из СУБД, что замедляло бы работу формы документа при ее открытии или изменении реквизитов.

Рекомендации по оформлению кода и повышению читаемости

Хотя компилятор встроенного языка «1С» безошибочно определяет приоритет выполнения операций (сначала выполняются операторы сравнения >=, затем логические И), для других разработчиков такой код может показаться сложным для быстрого восприятия. Чтобы повысить читаемость, рекомендуется отделять логические блоки круглыми скобками.

Рассмотрим более наглядный вариант написания той же строки:


РеализацияТоваровОблагаемыхНДСУПокупателя = (ДоговорКонтрагента.РеализацияТоваровОблагаемыхНДСУПокупателя) 
    И (ЭтотОбъект.Дата >= Константы.ДатаНачалаОперацийСТоварамиОблагаемымиНДСУПокупателя.Получить());

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

Управление интерфейсом на основе полученного булева значения

Проанализируем вторую часть кода из нашего примера — процедуру управления видимостью колонок на форме:


Процедура СкрытьНДСПриРеализацияТоваровОблагаемыхНДСУПокупателя()
    
    // В случае реализации лома, скрываются колонки СтавкаНДС, СуммаНДС, Всего
    ОбработкаТабличныхЧастей.УстановитьВидимостьКолонкиТабЧасти(мКолонкиТовары.СтавкаНДС, Не РеализацияТоваровОблагаемыхНДСУПокупателя);
    ОбработкаТабличныхЧастей.УстановитьВидимостьКолонкиТабЧасти(мКолонкиТовары.СуммаНДС, Не РеализацияТоваровОблагаемыхНДСУПокупателя);
    ОбработкаТабличныхЧастей.УстановитьВидимостьКолонкиТабЧасти(мКолонкиТовары.Всего, Не РеализацияТоваровОблагаемыхНДСУПокупателя);
    
    // ... и надпись ВсегоНДС
    ЭлементыФормы.НадписьВсегоНДС.Видимость = Не РеализацияТоваровОблагаемыхНДСУПокупателя;
    ЭлементыФормы.ВсегоНДС.Видимость = Не РеализацияТоваровОблагаемыхНДСУПокупателя;
    
КонецПроцедуры

Обратите внимание, как изящно здесь используется инверсия с помощью оператора Не. Нам не нужно писать условия вида:


Если РеализацияТоваровОблагаемыхНДСУПокупателя Тогда
    ЭлементыФормы.ВсегоНДС.Видимость = Ложь;
Иначе
    ЭлементыФормы.ВсегоНДС.Видимость = Истина;
КонецЕсли;

Мы просто передаем инвертированное булево значение в свойство Видимость элементов формы или в параметры процедуры управления видимостью колонок. Если значение реквизита РеализацияТоваровОблагаемыхНДСУПокупателя равно Истина, то в свойство Видимость передается значение Не Истина (то есть Ложь), и колонки скрываются. Если значение равно Ложь, то на форму передается Истина, и колонки отображаются.

Этот метод работает «в обе стороны» автоматически. Нам не требуется писать отдельные процедуры для скрытия и для показа элементов — один и тот же код корректно отрабатывает при любом изменении состояния документа.

Использование аналога тернарного оператора для небулевых значений

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

Однако и здесь можно избежать громоздких конструкций Если...Тогда. Для этого в платформе «1С:Предприятие» предусмотрена встроенная функция-аналог тернарного оператора — ?().

Синтаксис функции выглядит следующим образом:

Результат = ?(Условие, ЗначениеЕслиИстина, ЗначениеЕслиЛожь);

Пример использования функции:


// Определяем ставку НДС в зависимости от флага облагаемой операции у покупателя
СтавкаНДСДляЗаполнения = ?(РеализацияТоваровОблагаемыхНДСУПокупателя, Справочники.СтавкиНДС.БезНДС, Справочники.СтавкиНДС.НДС18);

Использование функции ?() совместно с прямым булевым присваиванием позволяет сделать программный код модулей 1С лаконичным, быстродействующим и соответствующим самым высоким стандартам разработки фирмы «1С».

← На главную