К статье
Практический материал

Разработка и Конфигурация · 9 мин

Чем отличается процедура от функции в 1С

Разбираем отличия процедуры и функции во встроенном языке 1С: возврат значений, синтаксис, директивы компиляции, типичные ошибки и критерии выбора.

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

Из этого единственного различия вытекает всё остальное: функцию можно вставить прямо в выражение (например, в условие или присвоение), а процедуру — нельзя. Попытка написать Результат = МояПроцедура(); приведёт к ошибке компиляции модуля. И наоборот, вызов функции как отдельного оператора с игнорированием результата технически возможен, но считается плохим стилем и часто маскирует логическую ошибку.

Ниже разберём синтаксис обеих конструкций, правила выбора между ними, особенности директив компиляции, типичные ошибки начинающих разработчиков и способы проверить корректность своего кода.

Синтаксис: как объявляются процедура и функция

Обе конструкции объявляются в модуле по похожему шаблону: ключевое слово, имя, список параметров в скобках, тело и завершающее слово. Для процедуры это Процедура ... КонецПроцедуры, для функции — Функция ... КонецФункции.

Функция РассчитатьСуммуСНДС(Сумма, СтавкаНДС) Экспорт

Возврат Сумма + Сумма * СтавкаНДС / 100;

КонецФункции

Процедура ЗаписатьОшибкуВЖурнал(ТекстОшибки) Экспорт

ЗаписьЖурналаРегистрации("МояПодсистема",

УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);

КонецПроцедуры

Ключевое слово Экспорт делает метод доступным из других модулей — без него процедура или функция видны только внутри своего модуля. Это правило одинаково для обеих конструкций. Параметры объявляются одинаково: через запятую, с возможностью указать значение по умолчанию (Параметр = 0) и модификатор Знач, который принудительно передаёт параметр по значению.

Единственное синтаксическое отличие внутри тела — оператор Возврат. В функции он обязан сопровождаться возвращаемым выражением: Возврат Результат;. В процедуре Возврат; используется без значения и только для досрочного выхода из тела метода.

Возврат значения — главное различие

Функция обязана вернуть значение на любом пути выполнения. Если написать функцию с ветвлением, где в одной из веток нет оператора Возврат, платформа не выдаст ошибку компиляции, но при выполнении такой ветки функция вернёт Неопределено. Это частый источник трудноуловимых дефектов: код работает, но результат периодически «пустой».

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

Типичные ошибки
01
Функция без «Возврат» в одной из веток условия — на выходе Неопределено и сбой логики вызывающего кода
02
Вызов функции как процедуры без использования результата — скрытая потеря важного значения, например признака ошибки
03
Попытка присвоить результат процедуры переменной — ошибка компиляции модуля
04
Возврат из процедуры значения через «Возврат Х» — синтаксическая ошибка, модуль не сохранится

Как вызываются: в выражении и отдельным оператором

Функцию можно встроить в любое выражение: присвоение, условие, параметр другого вызова, арифметическую операцию. Это делает код компактным:

Если РассчитатьСуммуСНДС(СуммаДокумента, 20) > Лимит Тогда

Сообщить("Превышен лимит");

КонецЕсли;

Процедура вызывается только как самостоятельный оператор: имя, параметры, точка с запятой. Она не может участвовать в выражениях, поэтому для получения результата от процедуры приходится использовать обходные пути — например, передавать параметр по ссылке (без модификатора Знач) и изменять его внутри. Такой приём работает, но ухудшает читаемость: у функции результат очевиден из места вызова, а у процедуры его нужно искать в списке параметров.

Маршрут решения

Как выбрать действие

Метод должен вычислить и отдать результат (число, строку, ссылку, булево)Объявляйте функцию с оператором «Возврат Результат»
Метод только выполняет действие: записывает объект, выводит сообщение, меняет реквизит формыОбъявляйте процедуру
Нужно вернуть несколько значенийИспользуйте функцию, возвращающую структуру, а не процедуру с кучей выходных параметров
Метод-обработчик события (ПриНажатии, ПередЗаписью)Используйте процедуру — платформа ожидает именно её

Директивы компиляции и контекст выполнения

И процедуры, и функции в модулях форм и команд снабжаются директивами компиляции: &НаКлиенте, &НаСервере, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста. Директивы работают одинаково для обеих конструкций и определяют, где будет выполняться код.

Различие проявляется в типичных сценариях применения. Серверные функции без контекста (&НаСервереБезКонтекста) — стандартный способ получить данные с сервера на клиент: клиентская процедура-обработчик вызывает серверную функцию, получает результат и обновляет форму. Процедуры чаще используются как обработчики событий формы и элементов — платформа сама генерирует их заготовки именно как процедуры, потому что обработчику не нужно возвращать значение (данные передаются через параметры события, например Отказ).

Экспортные методы и общие модули

В общих модулях размещают прикладной API конфигурации, и здесь выбор между процедурой и функцией особенно важен, потому что методом будут пользоваться другие разработчики. Принятый в типовых конфигурациях подход: функции — для запросов данных и вычислений (получить курс валюты, найти контрагента, рассчитать остаток), процедуры — для команд и действий (провести документ, отправить письмо, обновить служебные данные).

Такое разделение даёт предсказуемость: видя вызов функции, читатель кода ожидает, что она не меняет состояние базы, а видя процедуру — наоборот, готов к побочным эффектам. Нарушать это соглашение (например, делать функцию, которая рассчитывает сумму и заодно записывает документ) не запрещено платформой, но крайне не рекомендуется: вызов функции внутри выражения может выполниться в неожиданный момент, включая повторные вычисления.

Если функция обращается к базе данных, избегайте вызывать её в цикле по строкам таблицы — каждый вызов это отдельный запрос. Выгоднее один раз получить данные запросом с соединением и разложить результат в соответствие, а функцию использовать только для точечных обращений.
ПЗ
Практическое замечание

Проверка результата и отладка

Убедиться, что функция написана корректно, можно тремя способами. Первый — синтаксическая проверка модуля в конфигураторе (меню «Конфигурация — Проверка конфигурации» или кнопка проверки модуля): она поймает попытку вернуть значение из процедуры и вызов процедуры в выражении. Второй — отладка: точка останова на операторе Возврат покажет фактическое значение в табло. Третий — трассировка всех веток: проверьте, что каждый путь выполнения функции заканчивается возвратом осмысленного значения.

Для процедур главный критерий корректности — наблюдаемый эффект: запись появилась в журнале регистрации, документ провёлся, реквизит формы изменился. Если процедура изменяет параметры, переданные по ссылке, проверьте вызывающий код: значение переменной после вызова должно соответствовать ожиданию.

Контрольные точки

Как проверить результат

Все ветки функции завершаются оператором «Возврат»
Норма

На любом пути выполнения возвращается осмысленное значение

Тревожный признак

В одной из веток возврата нет — функция отдаёт Неопределено

Место вызова
Норма

Функция вызвана в выражении, результат используется; процедура — отдельным оператором

Тревожный признак

Функция вызвана как оператор, результат потерян

Побочные эффекты
Норма

Функция только вычисляет, изменения данных — в процедурах

Тревожный признак

Функция молча записывает данные в базу

Обработчики событий
Норма

Обработчик объявлен как процедура с параметрами события

Тревожный признак

Обработчик переделан в функцию — событие не сработает корректно

Частые вопросы

Может ли процедура вернуть значение через параметр?

Да. Если параметр объявлен без модификатора «Знач», он передаётся по ссылке, и изменения внутри процедуры видны вызывающему коду. Это рабочий приём, но при необходимости вернуть одно значение читаемее использовать функцию.

Что вернёт функция, если забыть оператор «Возврат»?

Значение «Неопределено». Ошибки компиляции не будет, поэтому такой дефект выявляется только при выполнении конкретной ветки кода — проверяйте все пути выхода из функции.

Можно ли вызвать функцию и проигнорировать её результат?

Технически платформа это допускает для методов, вызываемых как оператор, но встроенный язык в строгом смысле требует использовать результат функции. На практике вызов функции без использования результата — признак либо лишнего вычисления, либо потерянного признака ошибки.

Почему обработчики событий в 1С — процедуры, а не функции?

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

Что выбрать, если нужно вернуть несколько значений?

Функцию, возвращающую структуру с именованными полями. Это прозрачнее, чем процедура с несколькими изменяемыми параметрами: в месте вызова сразу видно, что именно получает код.

Влияет ли выбор между процедурой и функцией на производительность?

Нет, различие чисто семантическое, накладных расходов оно не создаёт. На скорость влияют обращения к базе данных и клиент-серверные вызовы внутри метода, а не тип конструкции.

Итог

Что важно запомнить

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