Код ждёт результат, а метод ничего не возвращает: разбор ошибки 1С
Содержание
Ошибка «Обращение к процедуре как к функции» означает одно: код пытается взять результат у метода, который ничего не возвращает. Например, Итог = Таблица.Свернуть("Номенклатура", "Сумма"); — Свернуть() это процедура, присвоить её «результат» нельзя. Исправление — убрать присваивание или переделать вызываемый метод в функцию.
Типичная ситуация: программист поправил общий модуль, обновил базу, а у бухгалтера при проведении документа или запуске внешней обработки вылетает окно с этой фразой. Причина почти всегда в одной строке кода, и найти её можно за несколько минут.
Чем процедура отличается от функции и откуда берётся ошибка
Во встроенном языке 1С есть два вида методов. Разница только в одном: возвращают они значение или нет.
| Процедура | Функция | |
|---|---|---|
| Объявление | Процедура Имя() … КонецПроцедуры | Функция Имя() … КонецФункции |
| Возврат значения | нет, Возврат только прерывает выполнение | Возврат Значение; |
| Вызов отдельной строкой | Имя(); | Имя(); — результат просто теряется |
| Вызов в выражении | ошибка | Х = Имя();, Если Имя() Тогда |
Отсюда правило: функцию можно вызвать как процедуру, а наоборот нельзя. Ошибка возникает, когда процедура стоит в любом месте, где нужно значение:
- 🔹 справа от знака
=:Результат = ЗаполнитьТовары(); - 🔹 в условии:
Если ПроверитьДанные() Тогда - 🔹 как параметр другого метода:
Сообщить(ОбновитьЦены()); - 🔹 в арифметике или конкатенации:
Сумма = Пересчитать() + 100; - 🔹 после
Возвратв функции:Возврат ЗаписатьДвижения();
Когда платформа её замечает
Момент обнаружения зависит от того, знает ли компилятор, что именно вызывается.
- ⚙️ При компиляции модуля. Если вызывается метод того же модуля или экспортный метод общего модуля, платформа видит его объявление. Ошибка всплывает при проверке синтаксиса, при сохранении конфигурации или при первом обращении к модулю.
- ⏱ Во время выполнения. Если метод вызывается у переменной (
Объект.Записать(),Таблица.Сортировать()), тип переменной известен только в момент работы. Тогда текст звучит какОбращение к процедуре объекта как к функциис именем метода в скобках, а в окне ошибки есть ссылка на модуль и номер строки.
Второй вариант коварнее: модуль компилируется без замечаний, а падает только в той ветке кода, до которой дошли данные конкретного пользователя.
Встроенные методы, которые чаще всего принимают за функции
Часто виноваты не собственные процедуры, а методы платформы. Привычка «метод что-то делает — значит, что-то возвращает» здесь подводит.
| Метод | Вид | Как правильно |
|---|---|---|
ТаблицаЗначений.Свернуть() | процедура | Таблица.Свернуть("Товар", "Количество"); — таблица меняется на месте |
ТаблицаЗначений.Сортировать() | процедура | Таблица.Сортировать("Дата Убыв"); |
Массив.Добавить() | процедура | Массив.Добавить(Значение); |
Структура.Вставить() | процедура | Структура.Вставить("Ключ", Значение); |
Соответствие.Вставить() | процедура | так же, без присваивания |
ЗаполнитьЗначенияСвойств() | процедура | ЗаполнитьЗначенияСвойств(Приемник, Источник); |
ДокументОбъект.Записать() | процедура | вызов в Попытка … Исключение, если нужен признак успеха |
Сообщить() | процедура | отдельной строкой |
А вот похожие методы-функции, с которыми путают в обратную сторону:
- ✅
ТаблицаЗначений.Добавить()— возвращает новую строку:НоваяСтрока = Таблица.Добавить(); - ✅
СписокЗначений.Добавить()— возвращает элемент списка. - ✅
Запрос.Выполнить()— возвращает результат запроса. - ✅
ТаблицаЗначений.Скопировать()— возвращает новую таблицу.
Если нужно и свернуть таблицу, и сохранить исходную, сначала сделайте копию: Итог = Таблица.Скопировать();, затем Итог.Свернуть(...). Присваивать результат Свернуть() бессмысленно, даже если бы платформа это пропустила.
Сомневаетесь в методе — поставьте курсор на его имя в модуле и откройте синтаксис-помощник. В описании метода у функции указан раздел «Возвращаемое значение», у процедуры его нет.
Поиск проблемной строки в конфигураторе и отладчике
Начните с текста ошибки. В окне сообщения платформа указывает модуль, номер строки и имя метода в скобках. Нажмите «Подробно», если окно свёрнуто: там же виден стек вызовов.
Проверка синтаксиса модуля
- Откройте в конфигураторе модуль, указанный в сообщении.
- Нажмите
Ctrl+F7— проверка синтаксиса текущего модуля. - Двойной щелчок по строке в окне служебных сообщений переносит курсор к месту ошибки.
Так ловятся вызовы процедур своего модуля и общих модулей.
Проверка всей конфигурации
Когда меняли общий модуль, который вызывают десятки мест, проверять модули по одному долго. В меню Конфигурация есть команда Проверка конфигурации…. Включите в ней логическую проверку и режимы, в которых работает код: сервер, тонкий клиент, внешнее соединение. После запуска в окне сообщений появятся все места с некорректными вызовами.
Проверка большой конфигурации типа ERP или КА занимает заметное время и нагружает компьютер. Запускайте её на копии или в нерабочие часы, если конфигуратор стоит на том же сервере, что и база.
Отладчик для ошибок времени выполнения
Если ошибка возникает только на конкретном документе, проверка синтаксиса её не покажет. Тогда:
- Запустите базу в режиме отладки из конфигуратора (
F5). - В меню
Отладкавключите остановку по ошибке. - Повторите действие пользователя: проведите документ, сформируйте отчёт.
- Отладчик остановится на строке с вызовом. Откройте стек вызовов и посмотрите, откуда пришли.
- Наведите курсор на переменную перед точкой: в табло виден её реальный тип. Часто выясняется, что там лежит не то, что ожидал автор кода.
Поиск всех вызовов по имени
Нашли процедуру-виновника — найдите и все её вызовы. Глобальный поиск по тексту модулей (Ctrl+Shift+F) покажет каждое упоминание имени. Отбирайте строки, где имя стоит после =, внутри Если, Пока или в скобках другого вызова.
Варианты исправления кода
Способ зависит от того, нужно ли вызывающему коду значение на самом деле.
Вариант 1. Результат не нужен — убрать присваивание
Самый частый и самый безопасный случай. Автор просто по привычке написал =:
// Было
Итог = Таблица.Свернуть("Номенклатура", "Количество, Сумма");
// Стало
Таблица.Свернуть("Номенклатура", "Количество, Сумма");
Итог = Таблица;
Если дальше по коду используется переменная Итог, присвойте ей сам объект, как во второй строке. Таблица после Свернуть() уже изменена.
Вариант 2. Результат нужен — переделать процедуру в функцию
Когда вызывающий код действительно ждёт ответ («прошла ли проверка», «сколько строк заполнено»), меняйте вызываемый метод:
// Было
Процедура ПроверитьЗаполнение(Документ)
Если Не ЗначениеЗаполнено(Документ.Контрагент) Тогда
Сообщить("Не указан контрагент");
Возврат;
КонецЕсли;
КонецПроцедуры
// Стало
Функция ПроверитьЗаполнение(Документ)
Если Не ЗначениеЗаполнено(Документ.Контрагент) Тогда
Сообщить("Не указан контрагент");
Возврат Ложь;
КонецЕсли;
Возврат Истина;
КонецФункции
Порядок действий:
- Замените
ПроцедуранаФункция, аКонецПроцедурынаКонецФункции. - В каждой ветке, где был голый
Возврат;, добавьте значение. - Добавьте
Возвратв конце тела. Без него функция, дойдя до конца, вернётНеопределено, и условиеЕсли ПроверитьЗаполнение(...)упадёт уже с другой ошибкой. - Сохраните модуль и проверьте синтаксис.
Старые вызовы отдельной строкой продолжат работать: функцию можно вызывать как процедуру.
Вариант 3. Метод чужой — разнести вызов и получение данных
Если процедура типовая или из библиотеки, менять её нельзя: следующее обновление сотрёт правку. Тогда вызовите процедуру отдельной строкой, а нужное значение возьмите из объекта, который она изменила, или из параметра, переданного по ссылке:
Параметры = Новый Структура("Результат", Неопределено);
ЗаполнитьПараметры(Параметры); // процедура меняет структуру
Итог = Параметры.Результат;
В 1С параметры передаются по ссылке, если в объявлении нет Знач. Типовые процедуры часто именно так «возвращают» данные — через параметр.
| Способ | Когда подходит | Риски |
|---|---|---|
| Убрать присваивание | результат не используется | почти нет |
| Процедуру → в функцию | свой код, значение нужно | забытый Возврат даст Неопределено |
| Разнести вызов | типовой или библиотечный метод | нужно понять, куда метод пишет данные |
Ошибка во внешних отчётах и обработках
Внешние файлы .epf и .erf не обновляются вместе с конфигурацией. Обработка, написанная под старый релиз, вызывает общие модули так, как они выглядели тогда. Если в новом релизе типовая функция стала процедурой или её заменили другим методом, ошибка появится при открытии или запуске.
Что делать:
- Откройте файл в конфигураторе через
Файл → Открыть. - Проверьте синтаксис модулей обработки и её форм тем же
Ctrl+F7. Проверка идёт с учётом общих модулей той конфигурации, которая открыта. - Для каждого вызова общего модуля откройте объявление метода (
F12— переход к определению) и сверьте вид и параметры. - Сохраните обработку под новым именем и проверьте в копии базы.
Отдельный случай — одинаковые имена. В модуле формы обработки объявлена своя процедура ЗаполнитьТаблицу(), а программист хотел вызвать одноимённую функцию из общего модуля, но написал имя без префикса модуля. Платформа выбирает метод текущего модуля, и вызов попадает в процедуру. Решение — вызывать с именем модуля: МойОбщийМодуль.ЗаполнитьТаблицу(), либо переименовать локальную процедуру.
У обработок от сторонних разработчиков сначала проверьте, нет ли у автора версии под ваш релиз. Ручная правка чужого кода потом мешает обновлять обработку.
Как не получить ошибку при рефакторинге
Ошибка почти всегда рождается при правке существующего кода: функцию упростили до процедуры, разделили метод на два, перенесли код в общий модуль. Несколько привычек снимают проблему.
- 🔍 Перед сменой вида метода найдите все вызовы. Глобальный поиск по имени, затем отбор строк, где результат используется.
- 🧩 Меняете процедуру на функцию — смело. Это безопасное направление: старые вызовы продолжат работать.
- ⛔ Меняете функцию на процедуру — только после правки всех вызовов. Каждое использование результата станет ошибкой.
- 🏷 Называйте методы по смыслу. Функции — существительным или вопросом (
СуммаДокумента(),ЕстьОстаток()), процедуры — глаголом действия (ЗаполнитьТовары()). По имени видно, можно ли брать результат. - 🧪 Запускайте проверку конфигурации перед выгрузкой обновления. Это ловит ошибку у вас, а не у пользователя.
- 🧱 Доработки — в расширения. Тогда после обновления типовой конфигурации платформа сама покажет, какие методы расширения перестали совпадать с основной конфигурацией.
Если команда работает в 1С:EDT, ошибка видна прямо в редакторе: строка подсвечивается сразу при наборе, до сборки и выгрузки.
Если исправление не помогло
Иногда код поправлен, а ошибка остаётся. Проверьте по порядку:
- Обновлена ли конфигурация базы данных. Изменения в основной конфигурации без
F7(обновление конфигурации БД) пользователи не увидят. - Не осталась ли старая версия в расширении. Расширение может перехватывать метод и вызывать его по-старому.
- Не та ли это обработка. У пользователя мог открыться файл с диска, а не исправленная версия из справочника дополнительных обработок.
- Тот ли это метод. При одинаковых именах в разных модулях легко поправить не тот. Переход
F12из строки с ошибкой показывает, какое объявление реально вызывается. - Не директива ли компиляции. Метод может быть объявлен по-разному в ветках
#Если Сервер Тогда … #Иначе. Посмотрите все ветки.