Разработка и Конфигурация · 10 мин
1С: что лучше — функция или процедура
Функция или процедура в 1С: в чём разница, когда что выбирать, типичные ошибки и примеры кода. Практическое руководство для разработчиков 1С.
В языке 1С (встроенный язык платформы 1С:Предприятие) есть два вида методов: процедуры и функции. Внешне они похожи — обе принимают параметры, содержат тело с кодом и вызываются по имени. Разница принципиальна: функция возвращает значение через оператор «Возврат», а процедура ничего не возвращает и используется только ради выполнения действий.
Вопрос «что лучше» на практике сводится к другому: нужно ли вызывающему коду получить результат вычисления. Если да — это функция. Если метод только выполняет действие (записывает объект, выводит сообщение, заполняет табличную часть) — это процедура. Попытка «вернуть» значение из процедуры через параметр или глобальную переменную — признак неудачного проектирования.
Выбор влияет не только на читаемость кода. Функции можно использовать в выражениях и условиях, процедуры — нет. При этом у функций есть ограничения в клиентском контексте управляемых форм: например, некоторые серверные вызовы и модальные операции ведут себя по-разному в зависимости от директив компиляции.
Чем функция отличается от процедуры в 1С
Синтаксически разница минимальна. Функция объявляется ключевым словом «Функция» и завершается «КонецФункции», внутри обязан быть хотя бы один оператор «Возврат <значение>». Процедура объявляется словом «Процедура», завершается «КонецПроцедуры» и может содержать «Возврат» без значения — только для досрочного выхода.
Ключевое поведенческое отличие — место использования. Функцию можно вставить в выражение: присвоить результат переменной, передать в другой метод, использовать в условии «Если». Вызов процедуры — всегда отдельный оператор, его нельзя включить в выражение.
Функция РассчитатьСуммуСНДС(Сумма, СтавкаНДС) Экспорт
Возврат Сумма + Сумма * СтавкаНДС / 100;
КонецФункции
Процедура ЗаписатьДокумент(ДокументОбъект) Экспорт
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
КонецПроцедурыЕщё одно отличие — семантика для читающего код. Когда разработчик видит функцию, он ожидает, что она вычисляет и возвращает значение без побочных эффектов. Когда видит процедуру — ожидает действие. Нарушение этого соглашения (например, функция, которая молча записывает данные в базу) затрудняет сопровождение конфигурации.
Когда выбирать функцию
Функция нужна всякий раз, когда результат работы метода потребуется дальше: сумма документа, найденная ссылка на элемент справочника, признак успешной проверки, структура с данными ответа. Если вы поймали себя на мысли «а как мне узнать, чем закончилось выполнение» — это функция.
Типичные сценарии для функций:
- расчёты: суммы, налоги, скидки, остатки;
- поиск и получение данных: найти контрагента по ИНН, получить курс валюты, выбрать остатки по складу;
- проверки условий: «МожноПровестиДокумент», «ЭтоПолноправныйПользователь» — функции, возвращающие Булево;
- формирование коллекций: массив ссылок, таблица значений, структура настроек.
Функции, возвращающие Булево, особенно удобны в условиях: «Если ПроверитьЗаполнение() Тогда». Такой код читается как фраза на естественном языке. Процедура с аналогичной логикой заставила бы заводить лишнюю переменную-флаг или передавать параметр по ссылке.
Когда выбирать процедуру
Процедура подходит для методов, которые выполняют действие и не обязаны отчитываться о результате значением. Вызвавший код просто ждёт завершения и идёт дальше.
Характерные примеры процедур:
- заполнение табличных частей и реквизитов формы;
- вывод сообщений, печать, формирование табличного документа;
- обработчики событий: «ПриЗаписи», «ПередЗаписью», «ПриОткрытии» — платформа вызывает их ради действия, а не результата;
- запись и проведение документов, если статус успеха отслеживается через исключения или отдельную проверку.
Обратите внимание на обработчики событий: многие из них в типовых конфигурациях объявлены процедурами, потому что платформа игнорирует возвращаемое значение. Делать такой обработчик функцией бессмысленно — результат никто не прочитает. Исключение — обработчики, где платформа ожидает значение, например «ОбработкаПроверкиЗаполнения» возвращает признак отказа через параметр, а не через возврат.
Как вернуть несколько значений: функция со структурой или процедура с параметрами
Частая дилемма: метод должен вернуть несколько результатов. В 1С функция возвращает одно значение, но это может быть составной тип — структура, массив или соответствие. Это предпочтительный путь: «Возврат Новый Структура("Успешно, ТекстОшибки, Ссылка", ...)" даёт вызывающему коду весь результат одним объектом.
Альтернатива — процедура с параметрами, переданными по ссылке (объявлены с ключевым словом «Знач» отсутствует, значит параметр изменяемый). Такой подход встречается в типовых конфигурациях, например «Отказ» в обработчиках. Он допустим, когда сигнатура продиктована платформой, но в собственном коде усложняет понимание: чтобы узнать, что метод изменяет параметр, придётся читать его тело.
Сравнение вариантов возврата нескольких результатов
Прозрачно и удобно: все результаты в одном объекте, вызов можно встроить в выражение. Ограничение — нужно знать ключи структуры.
Подходит для обработчиков платформы и совместимости со старым кодом. Минус — неочевидность: параметры меняются неявно, вызов нельзя встроить в выражение.
Компромисс для проверок: функция говорит «успешно/нет», детали уходят в параметр. Использовать умеренно.
Ограничения в клиент-серверном режиме и на форме
В управляемых формах директивы компиляции («&НаКлиенте», «&НаСервере», «&НаСервереБезКонтекста») применяются и к процедурам, и к функциям одинаково. Различий по производительности между ними нет — обе одинаково вызывают серверный вызов, если серверный метод вызывается с клиента.
Есть нюанс с асинхронной моделью: в тонком и веб-клиенте блокирующие (модальные) вызовы запрещены или ограничены. Если логика требует интерактивного вопроса пользователю, результат приходит через описание оповещения — и здесь часто удобнее процедура-обработчик оповещения, а функция с «немедленным» возвратом результата становится невозможной. Это стоит учитывать при проектировании клиентского кода.
Ещё одно ограничение: в общих модулях с признаком «Вызов сервера» доступны только экспортные методы, и сериализация возвращаемого значения функции должна поддерживаться платформой — нельзя вернуть, например, объект типа «ДокументОбъект» с сервера на клиент. Процедура в этом случае тоже не спасёт: проблему решают возвратом ссылки или структуры простых типов.
Как проверить, что выбор сделан правильно
Простой тест: посмотрите на место вызова. Если вызов записан как отдельный оператор и результат никуда не присваивается — должна быть процедура. Если результат присваивается переменной, передаётся дальше или участвует в условии — функция.
Второй тест — имя метода. Функции принято называть так, чтобы имя отвечало на вопрос «что вернёт»: «ПолучитьКурс», «РассчитатьСкидку», «НайтиКонтрагента». Процедуры — глаголом действия: «ЗаполнитьТабличнуюЧасть», «ЗаписатьДанные», «ВывестиСообщение». Если имя метода звучит как действие, но метод возвращает значение, стоит либо переименовать, либо пересмотреть тип метода.
Как проверить результат
Результат функции присваивается или используется; процедура вызвана отдельным оператором
Результат функции игнорируется постоянно — возможно, это должна быть процедура
Функция всегда завершается возвратом значения на всех ветках
Есть ветки без «Возврат» — функция вернёт Неопределено неявно
Функция только вычисляет, процедура только действует
Функция записывает данные или открывает диалоги
Типичные ошибки при выборе
Самая распространённая ошибка — функция без «Возврат» на одной из веток. Платформа не выдаст ошибку компиляции, но метод вернёт «Неопределено», что приведёт к трудноуловимым сбоям в вызывающем коде. Проверяйте, что каждая ветка логики завершается возвратом значения.
Вторая ошибка — возврат результата через глобальную переменную или реквизит формы вместо нормального «Возврат». Такой код работает, но ломается при повторных вызовах и параллельной логике. Третья ошибка — делать всё функциями «на всякий случай»: метод, который ничего не должен возвращать, но объявлен функцией, вводит читающего в заблуждение и провоцирует проверки результата, который всегда «Неопределено».
FAQ
Может ли процедура в 1С вернуть значение?
Нет, оператор «Возврат» в процедуре используется только для досрочного выхода без значения. Передать результат наружу можно через параметр, объявленный без ключевого слова «Знач» (передаётся по ссылке), но предпочтительный способ — преобразовать метод в функцию.
Что быстрее работает — функция или процедура?
Разницы в производительности практически нет: оба вида методов компилируются и выполняются одинаково. На скорость влияют серверные вызовы, обращения к базе данных и объём обрабатываемых данных, а не вид метода.
Можно ли вызвать функцию и проигнорировать её результат?
Технически да: вызов функции как отдельного оператора допустим. Но если результат систематически не используется, это сигнал, что метод либо должен быть процедурой, либо результат всё-таки нужно обрабатывать — например, проверять признак ошибки.
Что лучше для обработчиков событий формы?
Ориентируйтесь на платформу: если обработчик объявлен процедурой в типовой конфигурации или шаблоне конфигуратора, оставляйте процедуру. Платформа не читает возвращаемое значение таких обработчиков, поэтому функция смысла не имеет. Исключения прописаны в документации к конкретному событию.
Как вернуть из метода массив или таблицу значений?
Через функцию: таблица значений, массив, структура и соответствие — полноценные возвращаемые типы. При передаче с сервера на клиент учитывайте ограничения сериализации: таблицу значений иногда заменяют массивом структур для совместимости.
Нужно ли писать «Экспорт» у функций и процедур?
Ключевое слово «Экспорт» работает одинаково для обоих видов: оно делает метод видимым из других модулей. Добавляйте его только тем методам, которые являются программным интерфейсом модуля; вспомогательные методы оставляйте без «Экспорт».
Что важно запомнить
Выбор между функцией и процедурой определяется одним вопросом: нужен ли вызывающему коду возвращаемый результат. Нужен — функция, не нужен — процедура. Следите за возвратом значения на всех ветках функции, избегайте побочных эффектов в функциях и не передавайте результаты через глобальные переменные.