Код ждёт результат, а метод ничего не возвращает: разбор ошибки 1С

· 9 мин

Содержание

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

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

Чем процедура отличается от функции и откуда берётся ошибка

Во встроенном языке 1С есть два вида методов. Разница только в одном: возвращают они значение или нет.

ПроцедураФункция
ОбъявлениеПроцедура Имя() … КонецПроцедурыФункция Имя() … КонецФункции
Возврат значениянет, Возврат только прерывает выполнениеВозврат Значение;
Вызов отдельной строкойИмя();Имя(); — результат просто теряется
Вызов в выраженииошибкаХ = Имя();, Если Имя() Тогда

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

  • 🔹 справа от знака =: Результат = ЗаполнитьТовары();
  • 🔹 в условии: Если ПроверитьДанные() Тогда
  • 🔹 как параметр другого метода: Сообщить(ОбновитьЦены());
  • 🔹 в арифметике или конкатенации: Сумма = Пересчитать() + 100;
  • 🔹 после Возврат в функции: Возврат ЗаписатьДвижения();

Когда платформа её замечает

Момент обнаружения зависит от того, знает ли компилятор, что именно вызывается.

  • ⚙️ При компиляции модуля. Если вызывается метод того же модуля или экспортный метод общего модуля, платформа видит его объявление. Ошибка всплывает при проверке синтаксиса, при сохранении конфигурации или при первом обращении к модулю.
  • ⏱ Во время выполнения. Если метод вызывается у переменной (Объект.Записать(), Таблица.Сортировать()), тип переменной известен только в момент работы. Тогда текст звучит как Обращение к процедуре объекта как к функции с именем метода в скобках, а в окне ошибки есть ссылка на модуль и номер строки.

Второй вариант коварнее: модуль компилируется без замечаний, а падает только в той ветке кода, до которой дошли данные конкретного пользователя.

Встроенные методы, которые чаще всего принимают за функции

Часто виноваты не собственные процедуры, а методы платформы. Привычка «метод что-то делает — значит, что-то возвращает» здесь подводит.

МетодВидКак правильно
ТаблицаЗначений.Свернуть()процедураТаблица.Свернуть("Товар", "Количество"); — таблица меняется на месте
ТаблицаЗначений.Сортировать()процедураТаблица.Сортировать("Дата Убыв");
Массив.Добавить()процедураМассив.Добавить(Значение);
Структура.Вставить()процедураСтруктура.Вставить("Ключ", Значение);
Соответствие.Вставить()процедуратак же, без присваивания
ЗаполнитьЗначенияСвойств()процедураЗаполнитьЗначенияСвойств(Приемник, Источник);
ДокументОбъект.Записать()процедуравызов в Попытка … Исключение, если нужен признак успеха
Сообщить()процедураотдельной строкой

А вот похожие методы-функции, с которыми путают в обратную сторону:

  • ✅ ТаблицаЗначений.Добавить() — возвращает новую строку: НоваяСтрока = Таблица.Добавить();
  • ✅ СписокЗначений.Добавить() — возвращает элемент списка.
  • ✅ Запрос.Выполнить() — возвращает результат запроса.
  • ✅ ТаблицаЗначений.Скопировать() — возвращает новую таблицу.

Если нужно и свернуть таблицу, и сохранить исходную, сначала сделайте копию: Итог = Таблица.Скопировать();, затем Итог.Свернуть(...). Присваивать результат Свернуть() бессмысленно, даже если бы платформа это пропустила.

Сомневаетесь в методе — поставьте курсор на его имя в модуле и откройте синтаксис-помощник. В описании метода у функции указан раздел «Возвращаемое значение», у процедуры его нет.

Поиск проблемной строки в конфигураторе и отладчике

Начните с текста ошибки. В окне сообщения платформа указывает модуль, номер строки и имя метода в скобках. Нажмите «Подробно», если окно свёрнуто: там же виден стек вызовов.

Проверка синтаксиса модуля

  1. Откройте в конфигураторе модуль, указанный в сообщении.
  2. Нажмите Ctrl+F7 — проверка синтаксиса текущего модуля.
  3. Двойной щелчок по строке в окне служебных сообщений переносит курсор к месту ошибки.

Так ловятся вызовы процедур своего модуля и общих модулей.

Проверка всей конфигурации

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

Проверка большой конфигурации типа ERP или КА занимает заметное время и нагружает компьютер. Запускайте её на копии или в нерабочие часы, если конфигуратор стоит на том же сервере, что и база.

Отладчик для ошибок времени выполнения

Если ошибка возникает только на конкретном документе, проверка синтаксиса её не покажет. Тогда:

  1. Запустите базу в режиме отладки из конфигуратора (F5).
  2. В меню Отладка включите остановку по ошибке.
  3. Повторите действие пользователя: проведите документ, сформируйте отчёт.
  4. Отладчик остановится на строке с вызовом. Откройте стек вызовов и посмотрите, откуда пришли.
  5. Наведите курсор на переменную перед точкой: в табло виден её реальный тип. Часто выясняется, что там лежит не то, что ожидал автор кода.

Поиск всех вызовов по имени

Нашли процедуру-виновника — найдите и все её вызовы. Глобальный поиск по тексту модулей (Ctrl+Shift+F) покажет каждое упоминание имени. Отбирайте строки, где имя стоит после =, внутри Если, Пока или в скобках другого вызова.

Диагностика: выберите симптом

Варианты исправления кода

Способ зависит от того, нужно ли вызывающему коду значение на самом деле.

Вариант 1. Результат не нужен — убрать присваивание

Самый частый и самый безопасный случай. Автор просто по привычке написал =:

// Было
Итог = Таблица.Свернуть("Номенклатура", "Количество, Сумма");

// Стало
Таблица.Свернуть("Номенклатура", "Количество, Сумма");
Итог = Таблица;

Если дальше по коду используется переменная Итог, присвойте ей сам объект, как во второй строке. Таблица после Свернуть() уже изменена.

Вариант 2. Результат нужен — переделать процедуру в функцию

Когда вызывающий код действительно ждёт ответ («прошла ли проверка», «сколько строк заполнено»), меняйте вызываемый метод:

// Было
Процедура ПроверитьЗаполнение(Документ)
	Если Не ЗначениеЗаполнено(Документ.Контрагент) Тогда
		Сообщить("Не указан контрагент");
		Возврат;
	КонецЕсли;
КонецПроцедуры

// Стало
Функция ПроверитьЗаполнение(Документ)
	Если Не ЗначениеЗаполнено(Документ.Контрагент) Тогда
		Сообщить("Не указан контрагент");
		Возврат Ложь;
	КонецЕсли;
	Возврат Истина;
КонецФункции

Порядок действий:

  1. Замените Процедура на Функция, а КонецПроцедуры на КонецФункции.
  2. В каждой ветке, где был голый Возврат;, добавьте значение.
  3. Добавьте Возврат в конце тела. Без него функция, дойдя до конца, вернёт Неопределено, и условие Если ПроверитьЗаполнение(...) упадёт уже с другой ошибкой.
  4. Сохраните модуль и проверьте синтаксис.

Старые вызовы отдельной строкой продолжат работать: функцию можно вызывать как процедуру.

Вариант 3. Метод чужой — разнести вызов и получение данных

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

Параметры = Новый Структура("Результат", Неопределено);
ЗаполнитьПараметры(Параметры);   // процедура меняет структуру
Итог = Параметры.Результат;

В 1С параметры передаются по ссылке, если в объявлении нет Знач. Типовые процедуры часто именно так «возвращают» данные — через параметр.

СпособКогда подходитРиски
Убрать присваиваниерезультат не используетсяпочти нет
Процедуру → в функциюсвой код, значение нужнозабытый Возврат даст Неопределено
Разнести вызовтиповой или библиотечный методнужно понять, куда метод пишет данные

Ошибка во внешних отчётах и обработках

Внешние файлы .epf и .erf не обновляются вместе с конфигурацией. Обработка, написанная под старый релиз, вызывает общие модули так, как они выглядели тогда. Если в новом релизе типовая функция стала процедурой или её заменили другим методом, ошибка появится при открытии или запуске.

Что делать:

  1. Откройте файл в конфигураторе через Файл → Открыть.
  2. Проверьте синтаксис модулей обработки и её форм тем же Ctrl+F7. Проверка идёт с учётом общих модулей той конфигурации, которая открыта.
  3. Для каждого вызова общего модуля откройте объявление метода (F12 — переход к определению) и сверьте вид и параметры.
  4. Сохраните обработку под новым именем и проверьте в копии базы.

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

У обработок от сторонних разработчиков сначала проверьте, нет ли у автора версии под ваш релиз. Ручная правка чужого кода потом мешает обновлять обработку.

Как не получить ошибку при рефакторинге

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

  • 🔍 Перед сменой вида метода найдите все вызовы. Глобальный поиск по имени, затем отбор строк, где результат используется.
  • 🧩 Меняете процедуру на функцию — смело. Это безопасное направление: старые вызовы продолжат работать.
  • ⛔ Меняете функцию на процедуру — только после правки всех вызовов. Каждое использование результата станет ошибкой.
  • 🏷 Называйте методы по смыслу. Функции — существительным или вопросом (СуммаДокумента(), ЕстьОстаток()), процедуры — глаголом действия (ЗаполнитьТовары()). По имени видно, можно ли брать результат.
  • 🧪 Запускайте проверку конфигурации перед выгрузкой обновления. Это ловит ошибку у вас, а не у пользователя.
  • 🧱 Доработки — в расширения. Тогда после обновления типовой конфигурации платформа сама покажет, какие методы расширения перестали совпадать с основной конфигурацией.

Если команда работает в 1С:EDT, ошибка видна прямо в редакторе: строка подсвечивается сразу при наборе, до сборки и выгрузки.

Перед выгрузкой правки общего модуля
Выполнено: 0 / 5

Если исправление не помогло

Иногда код поправлен, а ошибка остаётся. Проверьте по порядку:

  1. Обновлена ли конфигурация базы данных. Изменения в основной конфигурации без F7 (обновление конфигурации БД) пользователи не увидят.
  2. Не осталась ли старая версия в расширении. Расширение может перехватывать метод и вызывать его по-старому.
  3. Не та ли это обработка. У пользователя мог открыться файл с диска, а не исправленная версия из справочника дополнительных обработок.
  4. Тот ли это метод. При одинаковых именах в разных модулях легко поправить не тот. Переход F12 из строки с ошибкой показывает, какое объявление реально вызывается.
  5. Не директива ли компиляции. Метод может быть объявлен по-разному в ветках #Если Сервер Тогда … #Иначе. Посмотрите все ветки.

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

Почему вызов функции без присваивания не даёт ошибки?
Платформа разрешает так делать: функция выполняется, а её результат просто отбрасывается. Обратное, использование результата процедуры, запрещено.
Можно ли проверить, процедура это или функция, не открывая код?
Да. Откройте синтаксис-помощник по имени метода. У функции в описании есть «Возвращаемое значение», у процедуры такого раздела нет.
Чем отличается текст «процедуры объекта» от обычного?
Обычный текст выдаёт компилятор для методов модулей. Вариант с «процедурой объекта» появляется во время выполнения, когда процедуру вызвали у переменной, например у таблицы значений.
Ошибка у бухгалтера, а программиста нет. Что сделать до его прихода?
Запишите текст окна целиком, нажав «Подробно», и действие, после которого оно появилось. Сам код пользователю не исправить, но точный текст сократит поиск до минут.
Может ли ошибка появиться в типовой конфигурации без доработок?
Редко, но бывает в отдельных релизах. Тогда обновитесь на следующий релиз или сообщите о проблеме разработчику конфигурации, не правя типовой код вручную.