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