Лямбда-функции на встроенном языке 1С
Разработка - Универсальные функции
Бесплатные
ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.
Узнавайте о новых бесплатных решениях в нашей телеграм-группе Инфостарт БЕСПЛАТНО
| Наименование | Скачано | Бесплатно |
|---|---|---|
|
Лямбда-функции на встроенном языке 1С:
.epf 11,23Kb ver:0.1
37
|
37 | Скачать бесплатно |
Вы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
«Анонимные функции, функции как переменные, методы для структур и соответствий, классы/прототипы, наследование! Где это всё?!» — спросите вы меня. И я уверенно отвечу: «Здесь». В этой теме ключ ко всему. Решение небольшое, элегантное, исключительно на встроенном языке 1С и как прививка от коронавируса: молодое, обнадеживающее, многообещающее, но еще не протестированное на массах. Поэтому прошу пока воспринимать всё, как альфа-версию, или даже, как концепцию. Кстати, под словом "Функция" здесь и ниже понимаются и процедуры тоже.
Имея опыт программирования на Python и JavaScript, страдаю, когда в 1С функция не может быть объектом первого класса. То есть, функцию нельзя поместить в переменную. Не результат выполнения функции, а саму функцию. Это лишает возможности передавать её, как параметр, в другие функции или программно создавать объекты c методами. Мы не можем ждать милости от 1С, и добавим нужные механизмы сами!
Материал будет разбит на несколько публикаций. Сегодня рассмотрим основу всей затеи — анонимную функцию.
Анонимные функции
Их еще называют лямбдами (λ). В отличие от привычных функций не имеют имен и определены непосредственно в месте вызова. В остальном точно такие же. Есть случаи, когда их удобнее использовать, чем именованные. Забегая вперед, покажу пару примеров.
//Каждое четное число в массиве умножить на 3
ForEach(Массив, "Если _1 % 2 = 0 Тогда Возврат _1 * 3; КонецЕсли;");
//Отобрать элементы, состоящие из заглавных букв:
НовыйМассив = Filter(Массив, "Возврат _1 = ВРЕГ(_1);");
ForEach и Filter — обычные функции. Как именно они написаны, покажу ниже. Сейчас важно отметить, что они обрабатывают массив с помощью анонимных функций (второй параметр). Это, во-первых, позволяет сократить код без потери читаемости, и, во-вторых, хранить и передавать тело анонимной функции куда нужно.
Пару дней назад я захотел в режиме предприятия написать произвольный код в поле ввода, нажать на кнопку, и чтобы этот код выполнился над списком отобранных объектов. Должен признаться, иногда я тайком использую команды Выполнить/Вычислить и в этот раз на них рассчитывал. Каково же было мое изумление, когда узнал, что эти конструкции не понимают таких важных вещей как: Возврат, Процедура, Функция! Тогда я создал функцию Lambda, которая умеет выполнять код с возвратами.
Lambda(Код, [Аргументы: _1, _2, … _n])
Суть такова. В эту функцию подается код в виде строки и аргументы по необходимости. К аргументам можно обращаться по номерам с подчеркиванием (например, _1). К сожалению, из-за особенности языка 1С максимальное количество аргументов определено заранее (в данных примерах — максимум 4). Все возвраты перед выполнением заменяются на конструкцию с использованием б-гомерзких (да будут они преданы забвению) операторов goto. Таким образом, результат возврата помещается в служебную переменную (ProgmaLambdaResult) и тут же осуществляется переход к концу функции Lambda, где происходит обычный возврат результата. В тексте переданного кода для повышения читаемости допускается заменять две двойные кавычки на символ ` (на клавиатуре, где Ё). Код считается "скомпилированным", если первый символ #.
//Пример использования:
// Lambda вызывается с тремя параметрами:
// Код,
// _1 = СписокОбъектов
// _2 = "Слава Тьюрингу!"
// Результат (Истина или Ложь) вернется в переменную ЕстьПрославлениеТьюринга
//
ЕстьПрославлениеТьюринга = Lambda("
|СтрокаПоиска = ВРЕГ(_2);
|Для каждого Значение из _1 Цикл
| Если Найти(ВРЕГ(Значение.Наименование), СтрокаПоиска) <> 0 Тогда
| Возврат Истина;
| КонецЕсли;
|КонецЦикла;
|Возврат Ложь;
|", СписокОбъектов, "Слава Тьюрингу!"
);
Вот так это сейчас реализовано:
//Функция возвращает результат выполнения Кода. Нумерованные параметры можно использовать для передачи произвольных значений,
// необходимых для выполнени кода. Возвращает Null по умолчанию.
//
// !!! Команда "Возврат" всегда должна писаться с заглавной буквы и закрываться ";" (точкой с запятой)
// !!! В Коде не должно быть команд: Функция, Процедура и их концов. Только тело.
//
//Параметры:
// Код - Строка - тело процедуры или функции
// _1 - произвольное значение (то же самое для _2, _3 ... _n)
//
Функция Lambda(знач Код, _1=Неопределено, _2=Неопределено, _3=Неопределено, _4=Неопределено)
ProgmaLambdaResult = null; // переменная, в которую вернется результат функции (если нужно)
// Код, начинающийся с символа # считается уже скомпилированным
Выполнить ?(Лев(Код, 1) = "#", Сред(Код, 2), CompileCode(Код));
~ProgmaLambdaReturn: // метка, к которой переходит алгоритм при возвратах
Возврат ProgmaLambdaResult;
КонецФункции
//Функция подготавливает код для выполнения в Lambda()
//
//Параметры:
// Код - Строка - код на языке 1С.
// Допускается для обозначений строк внутри кода вместо "" использовать ` (где ё).
// Код, начинающийся с # считается уже скомпилированным.
// Команда "Возврат" всегда должна писаться с заглавной буквы и закрываться ";" (точкой с запятой).
// Все Возвраты вне строк заменяются на специальные метки, необходимые для функции Lambda().
// В Коде не должно быть команд: Функция, Процедура и их концов. Только тело.
//
Функция CompileCode(знач Код)
Если Лев(Код, 1) = "#" Тогда
Возврат Код;
КонецЕсли;
Код = toCode(Код);
_Возврат = "Возврат";
ДлинаСловаВозврат = СтрДлина(_Возврат);
ПозицияВозврата = FindWithinCode(Код, _Возврат);
Пока ПозицияВозврата <> 0 Цикл
КодДо = Лев(Код, ПозицияВозврата-1);
КодПосле = Сред(Код, ПозицияВозврата + ДлинаСловаВозврат);
КонецКоманды = FindWithinCode(КодПосле, ";");
ЗначениеВозврата = Лев(КодПосле, КонецКоманды-1);
Если ПустаяСтрока(ЗначениеВозврата) Тогда // Процедуры
Код = КодДо + "Перейти ~ProgmaLambdaReturn" + КодПосле;
Иначе // Функции
Код = КодДо + "ProgmaLambdaResult =" + ЗначениеВозврата
+ "; Перейти ~ProgmaLambdaReturn;" + Сред(КодПосле, КонецКоманды+1);
КонецЕсли;
ПозицияВозврата = FindWithinCode(Код, _Возврат);
КонецЦикла;
Возврат Код;
КонецФункции
//Функция переводит Значение в вид, необходимый для выполнения в Lambda()
//
//Параметры:
// Значение - произвольное значение
//
Функция toCode(знач Значение)
Если Значение = Неопределено Тогда
Возврат "Неопределено";
КонецЕсли;
Если ТипЗнч(Значение) = Тип("Строка") Тогда
// Декодирование синтаксического сахара
Возврат СтрЗаменить(СокрЛП(Значение), "`", """");
КонецЕсли;
Возврат Значение;
КонецФункции
//Аналог функции Найти, только игнорирует текст внутри кавычек "" и комментарии.
//
//Параметры:
// Стр - Строка - Строка, в которой проводится поиск
// Подстрока - Строка - Строка, которую нужно найти
//
Функция FindWithinCode(Стр, Подстрока)
Накопитель = "";
ДлинаНакопителя = 0;
ДлинаПодстроки = СтрДлина(Подстрока);
ВнутриКавычек = Ложь;
ВнутриКомментрия = Ложь;
Для i = 1 по СтрДлина(Стр) Цикл
Символ = Сред(Стр, i, 1);
Если ВнутриКомментрия Тогда
Если Символ = Символы.ПС или Символ = Символы.ВК Тогда
ВнутриКомментрия = Ложь;
КонецЕсли;
ИначеЕсли Символ = """" Тогда
ВнутриКавычек = не ВнутриКавычек;
ИначеЕсли ВнутриКавычек Тогда
Продолжить;
ИначеЕсли Символ = "/" и Сред(Стр, i+1, 1) = "/" Тогда
ВнутриКомментрия = Истина;
i = i + 1;
Иначе
Накопитель = Накопитель + Символ;
ДлинаНакопителя = ДлинаНакопителя + 1;
Если ДлинаНакопителя = ДлинаПодстроки и Накопитель = Подстрока Тогда
Возврат i - ДлинаПодстроки + 1;
ИначеЕсли Накопитель <> Лев(Подстрока, ДлинаНакопителя) Тогда
Накопитель = "";
ДлинаНакопителя = 0;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат 0;
КонецФункции
Функции CompileCode и toCode выделены из Lambda, потому что будут нужны отдельно. Кроме этого используется вспомогательная функция FindWithinCode, которая работает как команда Найти, но игнорирует стрóки внутри строки и комментарии. Например, в возможной конструкции Возврат "Была выполнена команда Возврат;" при "компиляции" часть "Была выполнена команда Возврат;" должна остаться как есть.
Новые возможности
Используя функцию Lambda можно делать универсальные инструменты.
//Функция вызывает Код для каждого элемента Коллекции. Текущий элемент в Коде находится в переменной _1
//Если Код возвращает значение отличное от Null, в коллекции элемент заменяется.
//
//Например:
// Сообщить каждое значение: ForEach({Массив}, "Сообщить(_1)");
// Умножить каждое четное значение на 3: ForEach({Массив}, "Если _1 % 2 = 0 Тогда Возврат _1 * 3; КонецЕсли;");
//Параметры:
// Коллекция - Массив - пока только массив
// Код - Строка - текущий элемент коллекции находится в переменной _1.
// Возврат значения отличного от Null изменит элемент в коллекции
// _2 - произвольное значение - ..._n Нумерованные параметры можно использовать в Коде
//
Функция ForEach(Коллекция, знач Код, _2=Неопределено, _3=Неопределено, _4=Неопределено)
Код = "#" + CompileCode(Код);
Для i = 0 по Коллекция.ВГраница() Цикл
Значение = Lambda(Код, Коллекция[i], _2, _3, _4);
Если Значение <> null Тогда
Коллекция[i] = Значение;
КонецЕсли;
КонецЦикла;
Возврат Коллекция;
КонецФункции
//Функция возвращает коллекцию, состоящую из элементов Источника, которые удовлетворяют условию описанному в Коде.
//Текущий элемент в Коде находится в переменной _1
//
//Например:
// Отобрать четные числа: Filter({Массив}, "Возврат _1 % 2 = 0;");
// Отобрать строки, набранные заглавными буквами: Filter({Массив}, "Возврат _1 = ВРЕГ(_1);");
// Отобрать элементы, между параметрами _2 и _3 включительно: Filter({Массив}, "Возврат _2 <= _1 и _1 <= _3;", {Значение _2}, {Значение _3});
//
//Параметры:
// Источник - Массив - пока только массив
// Код - Строка - код должен возвращать значение, которое можно преобразовать в Булево
// _2 - произвольное значение - ..._n Нумерованные параметры можно использовать в Коде
//
Функция Filter(Источник, знач Код, _2=Неопределено, _3=Неопределено, _4=Неопределено)
Результат = новый Массив;
Код = "#" + CompileCode(Код);
Для каждого Элемент из Источник Цикл
Если Булево(Lambda(Код, Элемент, _2, _3, _4)) Тогда
Результат.Добавить(Элемент);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Цена
Заметно облегчая написание и чтение кода, данные анонимные функции, конечно, замедляют работу программы. Разница между вызовом классического кода и такого же, но командой Выполнить, минимум в 10 раз! На моих тестах замедление доходило почти до 25 раз. Но это всего лишь означает, что функции, созданные по данной технологии должны вызываться меньшее количество раз. Например, мою функцию ForEach можно переписать так, чтобы цикл был внутри лямбда-кода, тогда лишние сотые доли секунды, нужные директиве Выполнить на интерпретацию станут незаметными.
Отладка лямбда-кода затруднительна. Но анонимные функции не должны быть сложными.
«Боже! Боже! Это настолько нестандартно! Так на 1С не пишут! Кто нам позволит?» — скажут зануды. Вообще-то платформа 1С ценна не красотой и богатством синтаксиса, а распространенностью. А программирование само по себе подразумевает создание нужных абстракций, упрощающих работу. Я всего лишь планирую добавить десяток маленьких, но мощных функций, которые сильно увеличат возможности выражения мысли при кодировании.
Перспектива
Головокружительная! Уже сейчас я закончил функции, которые позволяют создавать специальные структуры, которые можно поместить в переменные и вызвать в другом месте. Эти структуры-функции можно вставлять в другие универсальные коллекции и вызывать с доступом к самому объекту-носителю (как self в Python или this в JS). Таким образом остается написать инструменты, которые будут понимать, что делать со свойством "Prototype" у объекта, и здравствуй, ООП!
// Тестируемый сейчас вариант создания и вызова функций
// newFunction(Параметры, Код) - создает специальную структуру
// Call(Структура, [Параметры]) - вызывает переданную функцию либо функцию из свойства Структуры
// Можно создать "функцию" и поместить её в переменную. Обычный код был бы таким:
// Функция ПервыйВВыборке(Выборка, ЗначениеПоУмолчанию=Неопределено)
// Возврат ?(Выборка.Следующий(), Выборка, ЗначениеПоУмолчанию);
// КонецФункции
//
ПервыйВВыборке = newFunction("Выборка, ЗначениеПоУмолчанию=Неопределено", // параметры функции
"Возврат ?(Выборка.Следующий(), Выборка, ЗначениеПоУмолчанию);" // код функции
);
Выборка = КакойТоКодДляПолученияДанных();
Call(ПервыйВВыборке, Выборка); // Данные выборки или Неопределено
Call(ПервыйВВыборке, Выборка, Ложь); // Данные выборки или Ложь
// Можно назначить структуре "метод"
_Объект = новый Структура("Имя, Фамилия, Представиться",
"Anton",
"Progma",
newFunction("Начало=`Hello! `", "Сообщить(Начало + `My name is ` + _.Имя + ` ` + _.Фамилия);"
)
Call(_Объект, "Представиться", "Hi."); // Hi.My name is Anton Progma
Call(_Объект, "Представиться"); // Hello! My name is Anton Progma
Пока этому всему пара суток отроду. Буду рад любым объективным мнениям. Прикрепил обработку для тестирования. Попрошу модераторов сделать её бесплатной для скачивания. Описание файла: обработка на управляемых формах с примером использования Lambda, ForEach и Filter (кнопки в командной панели формы). Слева — список элементов, который будут использовать ForEach и Filter. Посередине — область для лямбда-кода (оформляется по правилам 1С). Над областью кода — поле для списка параметров. Справа — лог, куда будет выводиться результат выполнения кода. Файл тестировался на платформе 8.3.16.1814
Планирую выпустить еще минимум 3 статьи по данной теме:
- Вспомогательные инструменты для упрощения кодирования и чтения.
- Функции первого класса, прототипы, наследование и, возможно, замыкания.
- Модули.
В перерывах жонглеры и фокусы!
Вступайте в нашу телеграмм-группу Инфостарт
См. также
Универсальные функции 1С 8.3 1С:Документооборот Россия Платные (руб)
ДО+ — расширение конфигурации, в котором собран постоянно пополняемый набор из 33 востребованных доработок для 1С:Документооборот КОРП 3.0: согласование задач прямо из мессенджеров MAX и Telegram, отзыв согласования и исполнения, гибкие повторные круги, эскалация с точностью до минут, контроль исполнительской дисциплины, выгрузка вложений в ZIP и склейка PDF, реестр документов в Excel, проверка дублей контрагентов и регистрационных номеров. Каждая возможность активируется отдельным флажком в режиме предприятия — включается только то, что нужно конкретной организации. Список функций расширяется с каждым релизом — текущая версия 2.1.0. Режим AddOn: типовая конфигурация не модифицируется, обновления ДО ставятся штатно, дополнительные лицензии и внешние компоненты не требуются. Внедрение силами администратора — около часа.
30000 руб.
09.07.2026 1411 1 0
Загрузка и выгрузка в Excel Универсальные функции Разработчик 1С:Предприятие 8 Россия Бесплатно (free)
Описанный ниже подход позволяет в три шага заполнять формулы в Excel файлы, вне зависимости от ОС сервера (MS Windows Server или Linux). Подход подразумевает отказ от работы с COM-объектом в пользу работы через "объектную модель документа" (DOM).
30.10.2025 8754 Abysswalker 11
Универсальные функции Работа с интерфейсом Разработчик 1С:Предприятие 8 Бесплатно (free)
Порой необходимо временно отключить расширение 1С, не удаляя его, чтобы не потерять данные. Но в этом случае при каждом запуске всем будет лезть уведомление о неактивном расширении, хотя очевидно, это техническая информация, которой не стоит лишний раз пугать пользователей.
14.05.2025 14495 DeerCven 16
Инструментарий разработчика Универсальные функции Запросы Разработчик 1С:Предприятие 8 1C:Бухгалтерия 1С:Бухгалтерия 3.0 1С:Зарплата и Управление Персоналом 3.x Бесплатно (free)
Внешняя обработка для создания запроса на основании табличных данных.
22.07.2024 11965 276 ixijixi 10
Универсальные функции Разработчик 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)
Благодаря этим пяти строчкам можно больше не заморачиваться с загрузкой из внешних файлов. Пользуюсь везде, всегда и постоянно.
21.05.2024 68778 dimanich70 87
Универсальные функции Разработчик 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)
Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.
1 стартмани
18.03.2024 9291 7 John_d 13
Универсальные функции Разработчик Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)
Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.
12.02.2024 85815 atdonya 31
Универсальные функции Разработчик 1С:Предприятие 8 Бесплатно (free)
На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.
30.11.2023 13484 ke.92@mail.ru 18
в последнем примере как 1С нику - вообще непонятно что и куда вызывается и через какие дороги идет. С хелло ворлд да забавно, а когда расчет себестоимости в эту портянку завернут будет - мозг сломаешь.
Не надо самим себе усложнять жизнь
Например передать функцию для сортировки в отдельный метод. Т.е. не «Если Тогда ИначеЕсли Тогда ИначеЕсли Тогда...», а просто применяется функция, которую передали параметром. Само собой можно и без переменной-функции, но с ней было бы проще. Что-то бы типа «ОписанияОповещения», только не CallBack'ом и для сервера
К примеру - пузырьковая сортировка массива структур. Это кроме как циклом с кучей условий - никак не сделать.
Задача: по кнопке сделать полностью типовую функцию, но с другой сортировкой в глубинах серверного модуля. В глубине типового, когда всё сортируется определенным образом, а нам надо по-другому.
Текущий способ единственный: вводим какой-нибудь «флаг» или дополнение (неважно), чтобы сортировка выполнялась с помощью другой функции. И собственно это нормальный рабочий вариант, не спорю. Но можно в самом начале кода (или как можно раньше) заменить вызываемую функцию на необходимую и она просто вызывается дальше. Т.е. суть не поменялась, но лезть глубже уже не надо. Абстракция как-никак. Например, типовые очень любят так делать с объектами оповещений: на форме создать оповещение «ПослеЧегоТоТам», в которое передаётся управление после девяти кругов ада по модулям конфигурации. Суть практически такая же
Если бы поддержка была - то архитектуру кода можно было бы выразить намного более правильным, читаемым и более легко поддерживаемом виде. Даже без ООП. И применить хотя бы методологию "Внедрения зависимостей", а там уже и до полноценного Аспектно-ориентированного программирования рукой подать (но там всё-же уже лучше ООП - хотя вот сейчас элементы АОП реализуются в расширениях и без поддержки ООП). Так же это прямой путь к обработке данных с тиле LINQ - лучшее из псевдо декларативных решений что я видел для универсальной обработки данных без текстовых строк (хотя в данном решении, конечно без текстовых строк не обойтись)
Без передачи своего кода и "Выполнить" требуется каждый раз писать отдельную функцию с циклом, дублируя логику обхода (там далеко не только цикл).
Хуже него только когда тексты запросов и когда хранятся в элементах спраовчниках в пердприятии.
И ты пытаясь разобраться в коде мечешься из конфигуратора в предприятие что бы понять как это все работает.
И код который внутрь строкового литерала завернут - это ж уже не код, который может проверять контроль синтаксиса?
А это значит что ты вынужден ловить синтаксические ошибки - в предприятии.
Т.е. поиск очепяток по Ctrl+F7 - бесполезен.
Я понимаю минусы. Но взять к примеру запросы. У них те же минусы. А из плюсов - конструктор запросов, но тоже с минусами. Это просто инструменты. Их можно не использовать, когда есть альтернатива. Может, у этой затеи тоже будут места применения.
Ты в конфигураторе убиваешь объект (ну или меняешь навазние пары ревизитов).
Все проверил (в конфигураторе) ... запускаешь ... и через пару дней пользователи ловят ошибку компиляции запроса.
Потому что поиск по конфигурации - не дал результатов. А текст запроса лежит в недоступном из конфигуратора месте.
И что делать в таком случае?
Ты в конфигураторе убиваешь объект
нет ну так точно не нужно делать , в смысле смешивать код конфигурации и код хранящийся где то в справочнике. Внешний код (справочник) , на мой взгляд , удобно использовать для решения различных мелких задач (команды , регламенты , хранилище разнородной информации, быстрое прототипирование итп ) наподобие подключаемых обработок.
Массив = Новый Массив;
Массив.Добавить(3);
Массив.Добавить(4);
Массив.Добавить(7);
Массив.Добавить(5);
Массив.Добавить(1);
Массив.Добавить(0);
Результат = ПроцессорыКоллекций.ИзКоллекции(Массив)
.Пропустить(1)
.Фильтровать("Элемент >= 5")
.Первые(2)
.Обработать("Результат = Элемент + 1")
.Получить(Тип("Массив")); ПоказатьЭто просто не нужно в 95% случаев. В отличие от, скажем, нормальной асинхронности.
Внимательно прочитал. Не смог понять, зачем нужны такие жертвы. Вот просто ни одного живого примера в голову не пришло.
Вообще забавный психологический профессиональный выверт. Каждый тащит в новую среду то, к чему привык в старой. Я, помнится, ещё на 7.5 пытался делать, как на Дельфи. Даже эмулировал привычные конструкции. А потом допетрил, что не надо изобретать слова для обозначения пальмы в чукотском языке, и льда со снегом - в суахили.
Ну некоторые приёмы ООП ещё да, пригодились бы, хотя и то, как показывает практика расширений, сие быстро превратилось бы в адъ и хаос. Но лямбда-функции?
Вы напоминаете человека, который говорит, что концепция степени числа не нужна в прикладной жизни, потому что есть умножение, а еще лучше -- сложение, которыми гораздо понятнее и подконтрольнее можно достичь того же результата. Мол, это математикам, может, и нужны степеня, а простым людям их не нать!
Я согласен, что в языке должна быть нормальная поддержка лямбда-функций. Как вы и сказали, в 1 случае из 20 такое может пригодиться. У меня даже, наверное, чуть реже, но периодически бывают моменты, когда этого не хватает.
Но это всё мечты...
По итогу - обычный синтаксический сахар через Выполнить.
Вместо того, чтобы изобретать такие велосипеды предлагаю автору писать сразу на
почему бы сразу не залепить в 1С свой лисп, кложур или ерланг. а как это нельзя, если на самом деле можно ))) ?
1. правильно ли я вас понял - вы написали кривоватый велосипед, а сейчас пытаетесь его защищать?
вы не можете ответить конкретно почему с вашим велосипедом код в 1С будет быстрее, лучше, понятнее.
2. где в типовых нужны анонимные функции, а главное - зачем?
3. зачем делать франкенштейна из ЯП, который для этого не имеет ни средств, ни назначения?
в дзен питона написано - простое, лучше чем сложное, это же кстати гласит принцип YAGNI, KISS и т д.
мои слова, подтверждает и тот факт, что в джаве, лямбды являются не более чем обертками над обычными коллекциями. можно писать и без них и будет быстрее.
Ваша ругань здесь не конструктивна, вас как обычно делают 1Серы - польют нечистотами, и ваша поделка дальше ИС никуда не пойдет. Более конструктивно и правильно - писать разработчикам платформы, правда они зададут те же вопросы, что и здесь.
1. Я защищаю не свою поделку, а полезность анонимных функций.
2. В "типовых" это где? Предлагается идея для упрощения программирования.
3. Зачем делать то, чего нет? Потому что нужно. Возможно, не вам конкретно.
Вот это вы точно шутите. Считайте, что я запостил тут кучу ржущих смайликов.
Кому нужно? Я сталкивался, пожалуй, со всеми областями применения 1С, кроме мобильной сферы, и не придумал, где бы было нужно.
Выглядит интересно, красиво, но практические применения приходится, скорее, специально придумывать, чем "о, боже, я давно хотел чтобы вот тут это было".
1. Инструмент полезен, когда он сконструирован правильно, то есть посредством самого ЯП. А ваш вариант - самодельный, вы его слепили из того что было.
2. В типовых конфигурациях. Я сейчас работаю на самописках, и там тоже слава боженьке, никто не завез функциональщину в вашем виде, т. к. это преимущественно ваша инициатива, которая тех, кто дописывает код сбивала бы с толку.
То есть вот это по вашему читаемее?
Map<String, Item> items =
futures
.stream()
.map(f -> {
try {
return f.get();
} catch (Exception e) {
logger.error("Error executing refresh task", e);
return (List<Item>) (List) Lists.newArrayList();
}
})
.flatMap(List::stream)
.collect(
Collectors.toMap(
i -> i.getName(),
i -> i,
(i1, i2) -> i1));
Ну, кому как, знаете ли.
3. Ради бога - чем бы дитя не тешилось как говорится. Но, вы так и не объяснили конкретно чем ваши лямбды лучше встроенных в ЯП средств.
2. Доказывать несостоятельность моего кода на каком-то чужом из другого языка - тоже не адекватно. Я как раз предлагаю писать языком 1С,если вы не заметили. Просто даю дополнительные возможности использования этого языка.
3. Я объяснил с примерами. Предложите другое универсальное решение функции filter
1. да, но ваш инструмент - это детский велосипед, на который сверху натянули контактные педали. зачем? потому что хочу.
я уже понял, что это чисто ваша хотелка, поэтому в очередной раз предложил написать разрабам платформы.
вы теряете время.
2. почему нет? давайте переведу на русский в стиле 1С.
если вы проектируете какую-то возможность в ЯП, будьте готовы к тому, что будут попадаться личности, которым эти возможности очень понравятся и они будут пихать их везде.
Соответствие Элементы =
Результаты.ВПоток().Сопоставить(Результат ->
Попытка
Возврат Результат.Получить();
Исключение
Сообщить("Ошибка при выполнении задачи обновления: " + ОписаниеОшибки());
Возврат Новый Массив;
КонецПопытки)
.Свернуть(Список.ВПоток)
.Собрать(ВСоответствие(
Элемент -> Элемент.Имя,
Элемент -> Элемент,
(Элемент1, Элемент2) -> Элемент1)); Показать3. универсальное решение в 1С через выполнить, только надо ли оно кому-то, кроме вас?
это и есть самый главный вопрос.
2. Мне не нужно переводить. Нужно добавить логику вашим примерам. Что с помощью чужого кода вы пытались сказать мне? Я так же могу его вам прислать обратно и обвинить, что вы виноваты в его существовании. Пример с личностями, которые бессмысленно используют инструменты опять не в кассу. Это не проблема разработчика.
3. Может, нужно. Может нет. Я не настаиваю на использовании, а делюсь информацией. У вас же позиция из разряда "не должно быть ничего, что я не понимаю". Очень самонадеянно.
2. логика в том, что если так могут написать, вам самому возможно придется в этом разбираться, что опять же говорит о целесообразности вашей поделки.
3. нет, логика в том - нужен ли велосипед, который работает через прослойку посредством выполнить, что добавляет лишний уровень абстракции и замедляет код. и замедление не стоит никому кроме вас не видного синтаксического сахара.
я знаю golang, java, python. писал что-то на javascript даже давненько. я понимаю инструменты, я не понимаю зачем лепить в 1С то, для чего он не предназначен.
я не решал ничего, я слишком маленький для этого человек, я сужу по решениям, которые написаны на этом языке. и это очевидно как бы.
ха, в вашем примере используется эксплойт от 1С - возможность выполнить любой код без контроля перед компиляцией.
ваши лямбды это не javascript лямбды, а eval(что-то). не надо так делать.
все верно.
знавал я одного PHP-программиста, который на каждое возражение архитектора расширял условия задачи таким образом, что задача становилась невыполнимой. кажется тут как раз ненужное преувеличение имеет место быть. спуститесь на землю - мы работаем на 1С.
Так это 1 уровень абстракции и для realtime приложений вряд ли подойдет питон. 1С - это абстракция над C++ и что дальше? а вот "Выполнить" в 1С - это уже 2 уровня абстракции.
ок, я понял.
тут был гомерический хохот. это типа "я обиделась"? я вас не знаю, как я могу о вас судить? я пожелал вам удачи с вашим великом.
(78)вы работает в 1с и вольны делать все что она позволяет, если вам это нужно. А не оглядываться на людей к коду которых у широкого числа аудитории есть вопросы. Уровень абстракции не важен. Если она удачная, значит нужна. Примите эти советы на прощанье
ок. я вас понял.
кстати, про eval:
Использование «eval»
В современной разработке на JavaScript eval используется весьма редко. Есть даже известное выражение – «eval is evil» («eval – это зло»).
Причина такого отношения достаточно проста: давным-давно JavaScript был не очень развитым языком, и многие вещи можно было сделать только с помощью eval. Но та эпоха закончилась более десяти лет назад.
Простите, но вы чушь несете. В старых версиях джавы лямбды в объекты анонимных классов заворачивались, в новых механизм получше уже. Но ни раньше ни сейчас они никак с коллекциями не были связаны вот вообще.
если мне не изменяет память, то лямбды - просто реализация анонимных классов, в идее можно даже превратить лямбду в реализацию функционального интерфейса.
коллекции не связаны с лямдами, это да. я тут ошибся. дальше что?
1. Что команда дает "возможность выполнить любой код без контроля перед компиляцией".
2. Что это абстракция загадочного 2го уровня.
Вы тут видите какое-то табу. Но я не улавливаю. Почему это всегда-всегда-всегда плохо? Я понимаю, что делает команда и пользуюсь ей именно поэтому. В этом смысл существования этой команды. Такова её природа. Даже самые педантичные в мире одинэсники из фирмы 1С не гнушаются. Так какие конкретные риски видите вы?
1. значит пишете потенциально опасный и неотлаживаемый код - вы и кто угодно через выполнить может обойти ту же синтаксическую проверку и сломать уже отлаженное, оттестированное решение, ошибившись запятой.
2. замедление - в моем универсальном парсере xml, написанном на 1С выполнить было самое медленное место, но этого требовала задача. я с радостью бы отказался от этого выполнить.
попробуйте в нагруженной среде свои лямбды.
матерые 1Сники используют этот выполнить только в тех задачах, где этого требует бизнесовая задача.
там, где можно обойтись без выполнить, они решают задачи средствами встроенного языка.
ваши недолямбды слава богу никто не догадался использовать.
т. к. там, где нет необходимости в усложнении, ее не делают.
я устал писать очевидные вещи.
2. Ээээ. Вы использовали Выполнить в своём проекте. Согласились с потерей скорости ради удобства. А мне запрещает) и это все в одном комментарии.
3. Я как раз матёрый и использую Выполнить там, где без него не обойтись. То что вам не нужны возможности писать код с анонимным функциями никак не означает потенциального запрета на это.
Отсюда и моё не понимание ваших аргументов: "мне можно, а вам нельзя!" и "это никому не нужно в 1с". Вы не аргументируетн, а противоречит сами себе
мои выполнить = этого требует задача и использование выполнить нельзя было заменить встроенными конструкциями языка.
ваши "лямбды" = можно заменить встроенными конструкциями языка.
Забейте, как публикация бесполезная вещь, так и ТС не воспринимает никаких аргументов.
"В интернете кто-то не прав" - всех не переубедишь, да и смысла в этом нет.
Хочет ТС верить, что он делает что-то полезное, да флаг ему в руки.
Запросы и обращение на сервер тоже замедляют работу. Это вопрос целесообразности использования. А не полный запрет. Когда время не критично, а удобство очевидно - почему надо отказаться от такого инструмента?
Проверка синтаксиса присутствует. Правда, только при исполнении.
Любой инструмент требует правильного обращения, чтобы не поаниться. Этот - необычный для 1с,поэтому под капотом у него хтоничечеие операторы. Но разве это отвечает на вопрос о необходимости принципиального отказа от всего кода, где есть Выполнить?
Про медоенную работу лямбды в цикле я писал. Данная реализация Filter нужна как можно проще для демонстрации идеи передачи инструкций между функциями.
Я изучу ссылку и отпишусь. Спасибо за важное уточнение!
Потенциальная угроза в виде программиста - ну так если он может изменить код конфигурации, то тут мы его никак не ограничим. Если вредоносное расширение или внешняя обработка - нужно ограничить право подключения. Если есть решение с вычисляемым кодом в формуле расчетного начисления - ограничить правом на изменение.
В общем угроза безопасности есть, но я не вижу как данное решение его увеличивает от имеющегося изначально.
А ведь по любому найдется долбоящер что будет передавать "лямбду" на сервер.
(221) Речь о инъекциях произвольного кода от программы имитирующей "клиент 1с". Если есть возможность передачи лямбды с клиента на сервер - значит такая имитация клиента может передать любой произвольный код на выполнение на сервере. Так что угрозу безопасности увеличивает.
не сказать, чтобы я в восторге от джавы - на ней удобно строить космический корабль, т. к. она буквально заставляет писать на ООП с самого начала, понятно почему ее в ентерпрайз любят - куча фреймворков на любой вкус.
меня на котлин звали из 1С на те же деньги недавно, но я котлина не знаю совсем, поэтому пришлось отказаться :(
а так, по стилю мне больше нравится golang, чем java.
да, Java - многословный динозавр, но сильна обратной совместимостью, кучей фреймворков и кросс-платформенностью.
многословность частично решается lombok'ом.
пока что я вижу, что Java пытается догнать современные языки, но вот эта обратная совместимость мешает, даже обещают fiber-нити, типа не такие тяжеловесные как стандартные потоки ОС (привет, Golang, кстати)
Корутины представляют собой простые C# итераторы, возвращающие IEnumerator и использующие ключевое слово yield. В Unity корутины регистрируются и выполняются до первого yield с помощью метода StartCoroutine. Дальше Unity опрашивает зарегистрированные корутины после каждого вызова Update и перед вызовом LateUpdate, определяя по возвращаемому в yield значению, когда нужно переходить к следующему блоку кода.
Не забываем ведь?))
КакаяТоПроцедура(КакаяТоФункция(КакойТоПараметр1,КакойТоПараметр2..КакойТоПараметрN),Еще параметры и функции);Что не так?
Но когда предлагают такую нетривиальную штуку, надо быть готовым сразу - чтоб всякие тупорылые автоматизаторы почуяли выгоду. Иначе впустую. Не мы такие - рынок такой.
я вообще, целый новый язык программирования делаю, и мнений всяких наслушался вдоволь... была и убийственная критика, и приятные комментарии, и слова поддержки, и главное - пользователи... люди разные и мнений много... и надо сказать, что убийственная критика иногда позволяет взглянуть на свою работу под новым углом и что-то переделать...
верите в свою правоту - продолжайте делать, а там как получится... к сожалению, причины взлётов и падений часто случайны...
даже люди, которые вкладывают в маркетинг миллионы, иногда ошибаются, например, в киноиндустрии хороший фильм может провалиться в прокате т.к. зрители пошли на соседний, успеха которого ни кто не прогнозировал...
Из практических минусов:
- потеря времени выполнения;
- потеря отладчика;
- потеря проверки синтаксиса.
Как следствие уменьшение комфорта работы пользователя и удорожание разработки и сопровождения.
И все ради трех-четырех процедур с сомнительной ценностью. Не дай Бог на такое в чужом коде налететь.
А еще в вашем случае надо помнить, что ForEach меняет коллекцию, а Filter возвращает новую. В погоне за универсальностью и гибкостью Вы начинаете создавать монстра, который с каждым шагом становится все более неповоротливым и тяжелым. То есть ваш пример
Для Каждого ЭлементКоллекции Из Коллекция Цикл
Выполнить("ЧтоТо");
КонецЦикла;
а это уже есть в платформе. Вот и выродилась идея.
Если вам в 1С не хватает Phiton или js, то либо возвращайтесь, либо привыкайте. Поверьте каждый из этих языков самодостаточен. Не надо в русский добавлять герундий или писать справа налево, просто привыкайте и будет легко и удобно.
Увы, но пока минус.
Потеря времени выполнения происходит при вызове команды Выполнить. Та же ситуация, что с запросами или обращениями на сервер -- каждый такой вызов занимает некое время сам по себе. Количество потерянного времени зависит от количества вызовов. Для ускорения нужно сокращать их количество, делая больше операций за раз. Но когда время не критично (доли секунды), можно, например, не в запросе делать преобразования значений, а в цикле по выборке из запроса. Это всё привычные компромиссы, и в данной теме замедление -- точно не главная проблема.
Механизм определения лямбда-функций нужен в основном, чтобы определять простой код. Если функция сложная, и её результат нужно отлаживать, то, само собой, выгоднее определить её обычным способом (и уже её вызывать в лямбде :) шучу). Я не предлагаю пользоваться лямбдами везде, но делюсь информацией, как можно не писать функции для каждой разновидности простого действия. То же самое касается и проверки синтаксиса.
Не понятно про комфорт пользователя и удорожание обслуживания. Вот 1С напишет запрос на 700 строк, который сложно осмыслить, вы же не откажетесь из-за этого от запросов в принципе. Я встречаю много незнакомого кода и типового, и не типового. Думал, у всех так же.
Это всё не ради 3-4 процедур. Это ради расширения возможностей. Приведенные примеры, как я думал, просты для понимания и распространены. Они служат для демонстрации технологии, и не являются конечным продуктом.
Я начинаю создавать библиотеку, как тысячи наших коллег. Обычная практика. Окажется ли результат монстром или конфеткой, не известно даже мне, а вам-то уж и подавно. Но я заинтересован, чтобы получилось как можно меньше букв и проще. Опыт программирования у меня есть, потому, есть и надежда. Тем более, что разработка публична, и меня поправят, когда допущу ошибку.
Единственное, что я добавляю в платформу, это анонимные функции. А вовсе не конкретную функцию Filter. Поэтому не вижу смысла сосредотачивать на ней внимание.
Очень смешно читать, что платформа и язык самодостаточны, когда они постоянно дополняются самим разработчиком. Очевидно, в 1С не считает, что достигли совершенства, а вы, значит, считаете. И я не добавляю ничего в язык. Всё написано на языке 1С, и технология предполагает использование языка 1С. Просто определение функций упрощается, когда это нужно.
Вы перепутали слова "самодостаточен" и "совершенен". Я имел ввиду не то, что им некуда развиваться, а то, что у каждого из этих языков есть своя философия применения и развития. И они не нуждаются в портировании не свойственных им технологий. 1С в в своей эволюции, например, отказалась от сериализации формы клиентского приложения, запретив тем самым ее передачу с клиента на сервер и обратно, а Вы хотите к каждой переменной добавить ее личные функции, тем самым увеличить передаваемые объемы информации между сервером и клиентом. И хочу заметить, что функция будет хранится в переменной, не как ссылка на область памяти в куче, а как строка неопределенной длины, то есть при копировании переменной будут создаваться копии функции, а не ссылки на нее.
Для понимания нужности, можете привести хотя два прикладных примера где будет применение вашего приема (плевать на скорость выполнения) удобней, читабельней, короче ну в чем-то лучше типового примера на ванильном 1С?
Я не склонен воспринимать программистов из фирмы 1С, как богов, у которых есть четкий план и которые дают нам всё, что только может понадобиться. А что они, дескать, не дали, то табу. Отказавшись от сериализации формы, они еще попутно отказались от сериализации... таблиц значений. А их представление о философии СтрРазделить сильно отличаются от питоновских: в 1С разделитель - это набор символов, каждый из которых разделитель (какой первый попадется). И по-вашему, если мне понадобится разбить строку по последовательности из двух символов, я не имею права написать аналог питоновского Split? Ну чепуха же! По этой же логике я считаю возможным добавлять любой нужный мне функционал.
Про экономию места в памяти как-то больше на придирку похоже. Во-первых, подозреваю, что вы сами не верите, что нужно так фанатично экономить память на коротких строках. Во-вторых, если вы имели в виду, что строка с кодом копируется из-за оператора Знач в параметре функции, так я рассчитываю, что не используемые строки будут удаляться из памяти сборщиком мусора после копирования. А если вы имели в виду, что строки будут копироваться при передаче между клиентом и сервером, ну такова природа клиент-серверных приложений. Массивы тоже копируются, что же нам их не пересылать?
Вы попросили 2 прикладных примера. Именно столько я и привел (Filter и ForEach). Я не могу взять в толк, почему вам и некоторым другим кажется, что эти примеры нельзя применить на практике? Чем они вам кажутся не применимыми?
Эти примеры не имеют никакой ценности в контексте того, что ради них придется использовать "100 строк библиотечного кода". В контексте только этих двух примеров использование анонимных функций ни разу не упрощает, а только усложняет как разработку, так и отладку.
Все равно немного не понимаете суть "претензий". Повторюсь: все вышеприведенное - это теория, а 1С - это не про теорию, а больше про практику. Все ждут, грубо говоря, куска кода, где будет применен ваш подход в рамках какой-нибудь реальной задачи, которая не обязательно будет интересна лично мне. Вот тогда будет виден реальный контекст применения подхода и можно будет по-настоящему оценить пользу - вот это будет интересно мне и, думаю, всем остальным. Пока это все теория ради теории.
Подход-то изначально чужд платформе, а данная реализация не вписывается в стандарты разработки, поэтому применение данного решения изначально сильно ограничено. Поэтому без реальных примеров и сравнительного анализа этих примеров с "классической" реализацией подавляющее большинство ограничится только знакомством с публикацией. Чего греха таить, я в том числе: новое-интересное люблю, но в данном случае отношусь пока скептически)
Давайте разберем примеры
Ваш код
//Каждое четное число в массиве умножить на 3
ForEach(Массив, "Если _1 % 2 = 0 Тогда Возврат _1 * 3; КонецЕсли;");
//Отобрать элементы, состоящие из заглавных букв:
НовыйМассив = Filter(Массив, "Возврат _1 = ВРЕГ(_1);");
Классический код
//Каждое четное число в массиве умножить на 3
Для Каждого ТекущийЭлемент Из Коллекция Цикл
Если ТекущийЭлемент % 2 = 0 Тогда
ТекущийЭлемент = ТекущийЭлемент * 2;
КонецЕсли;
КонецЦикла;
//Отобрать элементы, состоящие из заглавных букв:
НоваяКоллекция = Новый Массив;
Для Каждого ТекущийЭлемент Из Коллекция Цикл
Если ТекущийЭлемент <> ВРег(ТекущийЭлемент) Тогда
Продолжить;
КонецЕсли;
НоваяКоллекция.Добавить(ТекущийЭлемент);
КонецЦикла;
ПоказатьОригинальный код компилируется в момент обновления конфигурации или при загрузке внешней обработки, но только 1 раз, в вашем случае каждый раз выполняется проверка синтаксиса и компиляция. При этом Вы все равно используете именованные функции Фильтр(), ДляКаждого(), Лямбда(...), а не анонимную.
Теперь, как пример, нам нужно внести изменения, например, в первом случае вернуть новую коллекцию из увеличенных значений, а во втором случае попробуем получить новую коллекцию из массива не строк, а дат по условию - отобрать все вторники и четверги с начала второго квартала прошлого года до 28 августа 2020 года. Покажите как будет выглядеть функция Фильтр(...)? А я в ответ покажу как это сделать в классическом коде и сравним гибкость и простоту сопровождения.
Еще два маленьких вопроса на прямую не относящиеся к теме обсуждения:
1. Почему Вы переменные и функции именуете в перемешку на русском и английском, обычно такое не очень удобно сопровождать. Например EmployeesWithAWritOfExecution сложнее воспринимается, чем СотрудникиСИсполнительнымЛистом.
2. За что Вы так ненавидите оператор Перейти? Ведь этот оператор упрощает код, позволяя, например, выйти из вложенных циклов без дополнительных переменных-флагов и лишних условий.
p.s. Экономия места это не придирка. Я на самом деле считаю, что не нужно использовать памяти больше требуемого, а код лучше больше написать, чем больше исполнять.
Попробуйте мыслить в обратном порядке: вот есть Filter и ForEach. Стоит ли писать в 6 раз больше кода, если можно вызвать одну команду? Для меня ответ очевиден. Даже на этих 12 строчках вы умудрились сделать ошибку. А всё потому, что чем больше пишешь, тем больше ошибаешься чисто статистически.
Как будет выглядеть инструкция: "вторники и четверги с начала второго квартала прошлого года до 28 августа 2020 года" писать не буду. Это не имеет смысла и сожрет лишние калории. Очевидно, что так же, как и обычный 1С код, просто он будет внутри строки. Есть случаи, когда я посчитаю, что удобнее написать вызов функций из примера. А есть -- когда я сам решу, что так не удобно. Это просто инструмент. Не будет никаких клятв его использования минимум в 50% случаев! По желанию.
С русским и английским языком -- согласен, что не удобно переключаться. Сделать надо двуязычный интерфейс. На данный момент выделение имен английским языком удобно для разделения измерений. Типа, вот это платформа 1С (на русском), а вот это библиотека (на английском). В обычной практике я так не делаю.
Оператор перейти (признан не желательным оператором на территории 1С) должен сидеть в клетке, если уж кто-то его заводит. К нам пришел "стажер" старшего поколения, который вообще не понимал концепцию циклов, прерываний. Перейти во все поля! Я по возможности стараюсь не отходить от стандартов использования кода.
А про отбор и сортировку массива я уже сказал.
Сортировка: а) делаем получение свойств, по которым требуется сортировка, исходя из массива. б) делаем сортировку.
Отбор: а) делаем получение свойств, по которым требуется отбор, исходя из массива. б) делаем отбор.
Просто, прозрачно, управляемо, декомпозируемо.
Написана процедура, получающая в качестве параметра выгружаемый документ. В ней развесистый case примерно такого вида:
Если Документ.ВидОперации = Перечисления.ВидыОпераций.Вид1 Тогда
ДокументXDTO = ОбработатьВид1(Документ);
ВызватьМетод1(ДокументXDTO);
ИначеЕсли Документ.ВидОперации = Перечисления.ВидыОпераций.Вид2 Тогда
ДокументXDTO = ОбработатьВид2(Документ);
ВызватьМетод2(ДокументXDTO);
1. Подготовительные действия;
2. Выборка данных и формирование ДокументXDTO;
3. Завершающие действия.
Пункт 1 повторяется во всех функциях с отличием только в имени типа XDTO, п 3 повторяется во всех функциях без отличий.
Если бы была возможность передавать функцию в качестве параметра, то вместо 8 функций ОбработатьВидN() я бы написал одну, передавая в неё в качестве параметра функцию реализующую только выборку данных и формирование объекта XDTO. А п.1 и 3 присутствовали бы в коде только 1 раз. Да, функций выборки осталось бы 8, но они были бы компактными, легко читаемыми и без повторов.
Вы опять не поняли или сделали вид. У Вас есть две функции и библиотека. Первая функция изменят элементы коллекции, вторая отбирает их. Очень, скажем, узкий функционал. Вот я и предлагаю чуть-чуть усложнить задачу и изменить отобранные значения. Придется дополнять библиотеку? То есть полезем в 100 строк кода? Было интересно, получится ли у Вас с первого раза засунуть в константную строку кода проверку на фиксированную дату.
Я не пытаюсь сказать, что, то, что Вы делаете - плохо. Я только пытаюсь донести, что конструкция получается тяжелее, чем классическая реализация. Если это делается ради задачи из постановочной части статьи, то проще использовать обработку "Групповое изменение объектов" БСП. Она умеет выполнять произвольный алгоритм над коллекцией прикладных объектов "из коробки".
Кстати, не покажите мне мою ошибку?
Напишите строку кода с датой типа '20210101' , потом поставьте по бокам кавычки - получится лямбда-код. В чем эксперимент?
Ваша ошибка не в синтаксисе, а в данных. Видите, как нелегко сориентироваться, когда букв много.
Если вы не видите разницы между тем, что написали и что хотели написать, то я рекомендую все-таки подумать о пользе сокращения кода. Это реально помогает с разработкой и поддержкой. Лучше вызов одной незнакомой в первый раз функции, чем 6 команд обычного кода.
Я с трудом верю, что мы так долго спорим о пользе выноса повторяющегося кода в функцию.
Если Документ.ВидОперации = Перечисления.ВидыОпераций.Вид1 Тогда
ДокументXDTO = Обработать(Документ, ТипXDTO1, ФункцияВыборки1());
ВызватьМетод1(ДокументXDTO);
ИначеЕсли Документ.ВидОперации = Перечисления.ВидыОпераций.Вид2 Тогда
ДокументXDTO = Обработать(Документ, ТипXDTO2, ФункцияВыборки2());
ВызватьМетод1(ДокументXDTO);
...
КонецЕсли;
Функция Обработать(Документ, ТипXDTO, ФункцияВыборки())
// Подготовительные действия, используется ТипXDTO
...
ФункцияВыборки(Документ, ДокументXDTO);
// Завершающие действия
...
Возврат(ДокументXDTO)
КонецФункции
ПоказатьИ 8 штук ФункцияВыборкиN(), компактных, в пределах 40 строк.
ФункцииОбработки = Новый Соответствие;
ФункцииОбработки.Вставить(Перечисления.ВидыОпераций.Вид1, ФункцияВыборки1);
ФункцииОбработки.Вставить(Перечисления.ВидыОпераций.Вид2, ФункцияВыборки2);
ФункцииОбработки.Вставить(Перечисления.ВидыОпераций.Вид3, ФункцияВыборки3);
...
ДокументXDTO = Обработать(Документ, ТипXDTO1, ФункцииОбработки.Получить(Документ.ВидОперации))
ПоказатьЕстественно ФункцияВыборки1 здесь - это где-то выше описанные функции, которые здесь просто передаются в другую функцию "Обработать" как параметр и будут вызываться где-то внутри по типу:
...
Результат = ФункцияВыборки1(Документ, КакойТоПараметр1, КакойТоПараметр2)
...
Обработать(Документ, ТипХДТО)
// где внутри написано
Режим=Документ.ВидОперации;
Если Режим=Перечисления.ВидыОпераций.Вид1 Тогда
ФункцияВыборки1
ИначеЕсли Режим=Перечисления.ВидыОпераций.Вид2 Тогда
ФункцияВыборки2
//итд.
ПоказатьНу вот не вижу смысла городить огород. Я долго отучал себя от красивостей в пользу простоты, читабельности и управляемости.
(217)Еще раз. Можно и так и будет работать. Но выразительнее и компактнее без двух десятков Если...Иначе
В мире 1С конечно нам так привычнее, мы по другому не можем. И любые "придумки" как у автора воспринимаются дурным тоном.
Но в других языках, где это можно и прогерам это привычно, этим пользуются. Это удобнее, нагляднее.
Но опять же не обязательно. Не хочешь, не пользуешься, пишешь 20 штук if...else... Только там уже такой вариант считается дурным тоном )) Дуальность ))
Опять же без нативной реализации внутри языка 1С, мне тоже эта затея кажется сомнительной с точки зрения практической реализации. Автор видимо считает иначе, поэтому посмотрим на развитие сей затеи.
А тебе реализовать такой функционал сбоку не получится. Даже внешней компонентной. Тебе же туда передавать надо не примитивные данные а ссылки и доступ из твоих функций должен быть к данным 1С. поэтому максимум, что ты можешь сделать - это библиотеку на языке 1С внутри конфигурации. С точки зрения производительности - это всегда будет проигрывать. Но где производительность не важна, будет прикольно. Ну и куча хейта тоже обеспечено
Я вам сейчас пример приведу. Я пишу код, не ставя пробелы вокруг операндов и порой после запятых тоже. Код - компактный. На маленьком мониторе чудо как удобно. Но разве удобно людям после меня иметь дело с таким моим стилем написания? Да ни разу.
Повторю, 1с-нику непривычно. И воспринимается "злом". Но это вопрос привычки.
Для 99% 1С-ников это будет "чудо странное". Но другом языке выглядело бы вполне обычно.
В 1С когда-то не было асинхронных вызовов. Сейчас вся конфы ими утыканы. Когда-то писали без разделения на клиент и сервер. Сейчас такое трудно встретить.
Поэтому выразительность - это не только вопрос возможностей и ограничений языка, но и принятых практик в сообществе. В 1С сейчас они такие, но мир не стоит на месте.
Ага, во многих языках это норма. Но при этом зачастую страдает качество решения задач в целом - думаю, очевидно, почему. И, увы, правы те, кто ругает однобуквенные переменные.
Пример на котлин:
fun List<Document>.filterAndProcessForOperationKinds(kinds: Set<OperationKinds>, processLambda: Document.()->Unit): List<Document> = filter { it.operationKind in kinds}
.apply {
forEach(processLambda)
}
Фильтруем только по переданным видам документов, выполняем какое то действие переданное извне в лямбде (провести, пометить на удаление, распровести, поменять значение поля и сохранить, что угодно, вариантов много) список документов для дальнейшей работы возвращаем.
Примеры использования функции
val filteredDocs = documents.filterAndProcessForOperationKinds(setOf(OperationKinds.Kind1, OperationKinds.Kind2)) {
deleteMark = false
someField = someValue
save()
}
Для документов с определенным видом операции снимаем пометку удаления, устанавливаем значение какого то поля в одно значение для всех отфильтрованных документов, сохраняем. Код в фигурных скобках естественно может быть любым абсолютно, в одном месте конфигурации нужно одно действие для отфильтрованных документов, в другом другое.
И это очень простой пример, применений можно сколько угодно придумать. Это же азы программирования обобщать и абстрагировать.
я же не говорю удалить все СКД и заменить на простые инструкции.
В алгоритмах у вас не бывает, где нужно обойти что-то в цикле и сделать какие-то манипуляции с условиями?
Если не бывает, значит не ваша реальность. У меня бывает.
Ту же сумму и налоги в табличной части по всем строкам пересчитать.
Выше вам коллега писал, что у него несколько типов документов на входе и ему надо обработать каждый индивидуальной функцией
Вот вы "тонны кода" в рамках какой задачи, простите, писали?
Когда я с 1с работал - писали в франче несколько своих конфигураций отраслевых.
Для себя запишу, реализовать пример функции Case
Да, без них можно. Но с ними было бы изящнее. Можно было бы писать более кратко, более ёмко.
Увидел в статье автора попытку именно посмотреть как было бы удобно, если бы были анонимные функции. И попытку реализовать прототип такой концепции. Конечно, в массовом продакшене без реализации в ЯП 1С это вряд ли применимо. Причины описалы выше: производительность, неудобство отладки. Но в некоторых небольших решениях, как эксперимент было бы интересно.
Может 1С, когда-нибудь и реализует это в языке
сверлить отверстия болгаркой это не фантазия - это
ForEach(Массив, "Если _1 % 2 = 0 Тогда Возврат _1 * 3; КонецЕсли;");
Функция ForEach(Коллекция, знач Код, _2=Неопределено, _3=Неопределено, _4=Неопределено)
Код = "#" + CompileCode(Код);
Для i = 0 по Коллекция.ВГраница() Цикл
Значение = Lambda(Код, Коллекция[i], _2, _3, _4);
Если Значение <> null Тогда
Коллекция[i] = Значение;
КонецЕсли;
КонецЦикла;
Возврат Коллекция;
КонецФункции
Показать
//Отобрать элементы, состоящие из заглавных букв:
НоваяКоллекция = Новый Массив;
Для Каждого ТекущийЭлемент Из Коллекция Цикл
Если ТекущийЭлемент <> ВРег(ТекущийЭлемент) Тогда
Продолжить;
КонецЕсли;
НоваяКоллекция.Добавить(ТекущийЭлемент);
КонецЦикла;
Показатьпо сути Вы пытаетесь сделать обертку на обычный цикл, инкапсулируя его в свою функцию, которую каждый раз придется писать так как она не входит в неизменяемую часть кода, которую громко именуете библиотекой. Которая, кстати, по своей сути является парсером для переданной строки. Количество строк можете посчитать сами. И Вы так и не объяснили где ошибка в данных, которые я даже не приводил.
Полностью с Вами согласен, что наш диалог несколько затянулся. Поэтому больше не буду отвлекать Вас. Тем более, что Вы ни разу не ответили на прямо поставленный вопрос, а только обвинили в ошибках и отсутствии фантазии.
1. Пост предлагает рассмотреть возможность использования в 1С инструментов, которые широко применяются в мире, но не реализованы в 1С. Это анонимные функции.
2. Это первый пост, посвященный краеугольному камню всей задумки -- АНОНИМНЫМ ФУНКЦИЯМ. Внимание! Только анонимным функциям.
3. Приведенные примеры Filter и ForEach хоть и выполняют заявленную для них работу, но представлены в очень простом виде. Функция Filter является классическим инструментом для использования других функций, как параметра. На ней легко показать пример такого взаимодействия между функциями. Только за этим Filter в публикации. С ней бесполезно бороться, потому что смысл поста вообще не в этой функции (а в анонимных функциях). Я не собираюсь её использовать в такой реализации (может быть, её аналог, но не этот конкретный Filter). Перестаньте её кусать, она и так неживая! Я предлагал и предлагаю сосредоточиться на самой идее передачи в качестве параметра программных инструкций! Чтобы потом сокращать код анонимными функциями, где это целесообразно.
4. Я использую слово "Библиотека" потому что оно нейтральное и передает суть. Слово "модуль" в 1С подразумевает конкретные сущности. А сейчас я понятия не имею, куда лучше сложить этот код. И это не важно. Речь о технологии работы с анонимными функциями.
5. Я не пытаюсь доказать, что представленная реализация использования анонимных функций единственно верная и должна повсеместно использоваться. Мне нужен инструмент. Если он появится в платформе или кто-то сделает лучше я буду только рад.
6. Сейчас спор между нами идет в двух измерениях. Я говорю, что сокращение повторяющегося кода через вынос его в отдельные функции - это всем известное благо, и если делать вот так, то можно в качестве параметра передавать алгоритмы, а не только данные! Вы же говорите, что вам не нравится Filter. И мне, как рабочий инструмент, он не нравится, но как простой пример использования анонимных функций - зашибись.
7. Вы мне подарили отличную иллюстрацию утверждению, что чем меньше кода, тем легче сопровождать и разрабатывать. До последнего вы настаиваете, что нет никаких проблем, написать лишний цикл с условием. Это, мол, привычно и легко всеми воспринимается. Но при этом вы сами не способны увидеть маленькую опечатку в собственном коде, про ошибку в котором вам сказали. Код менее чем в 20 строк. Он элементарный, он написан вами в самом удобном для вас виде. И вы полдня не можете найти, что желая умножать четные числа на 3 (это в моем примере, который вы транслировали, и у вас в комментарии), умножаете их на 2. Я понимаю, что ваш пример был о другом, но когда речь зашла о том, что в этом коде ошибка, вы не смогли её увидеть! Поэтому я и настаиваю, что уменьшение количества кода за счет использования универсальных функций - важно. А лишние доли секунды на компиляцию и лишние байты на хранение кода -- это несущественная капля в море.
8. Цель публикации не в продаже идеи. А в призыве публично её обсудить, найти изъяны, прикинуть перспективы. А вы отвлекаете внимание и тратите силы на вопросы, которые где-то сбоку. Я пытаюсь вернуть вас в русло.
Только пара замечаний:
1. Не используйте оператор "Выполнить" - всегда используйте встроенную функцию "Вычислить"- т.к. "Выполнить" не работает в WEB-клиенте и на мобильном клиенте.
2. Функция "Вычислить" не работает и под iOS вообще - вот тут лямбда функции никак не прикрутить. Но можно ограничено прикрутить передачу ссылок на готовые функции через "ОписаниеОповещения" и вызов через встроенную функцию "ВыполнитьОбработкуОповещения" - но это очень ограниченное применение получается (см синтаксис-помощник), но будет работать на iOS
P.S.
Но сам пришёл в выводу, что расширять язык 1С типовыми путями почти бесполезно. Нужно расширять компилятор 1С. Но.... байткод доступен для ограниченных мест метаданных - значит нужна кодогенерация - в общем та ещё ...опа! Связываться тоже пока не хочется. Хотя идея перенести язык Kotlin в платформу 1С Предприятие 8 меня пока не покидает
2. Что касаемо применимости для себя: если бы я подумывал начать пользоваться при разработке изложенными здесь идеями и механизмами, первое, что остановило бы меня - проблемы при отладке. Как инженер, использующий произвольный код, как доставшийся в наследство, так и внесенный мной, предполагаю, что высока вероятность, что польза от применения пусть самых божественных абстракций, взятых из лучших практик идеальных языков программирования и прочее, могут перекрыться ухудшением читаемости кода и увеличением затрат на отладку. Ну, и порог входа на обслуживание этого кода увеличивается, но это до кучи уже.
Всё или почти всё это коллеги уже писали выше, просто еще одно скромное мнение.
3. Если я заподозрен в каком-то скепсисе, критике или типа того - см. пункт 1.
Если использовать нормальную функцию, то будет еще и отладка :)
Несмотря на то, что в статье указано на использование оператора Вычислить, в коде я его не увидел. Между тем, в отличии от Выполнить, Вычислить работает везде: в вебе, в мобильных (iOS, Android).
Хотелось бы увидеть примеры, где автору реально помогла такая абстракция. Что-нибудь в виде, вот задача, которая решается обычным алгоритмом вот так, а при применении Лямбда все становится проще :)
Хотя автор и утверждает, что объяснение полезности - это не цель статьи, мол в других языках и в общедоступной практике программирования это уже давно признанный факт, - применительно к 1С это все-таки может быть не так. Слишком чуждое в среде 1С решение, какое бы полезное не было в других местах, может оказаться на практике громоздким и неуклюжим на 1С :)
Если использовать предопределенную переменную, то код не может быть универсальным. А если написать обычную функцию, то её нельзя передать.
Про полезность, надеюсь, станет понятно в дальнейшем развитии темы.
Жду продолжения темы :)
Дело не в абстрактном мышлении. Дело в условиях задач и их практике - наработанной, проверенной, испытанной - практике. Вот, к примеру, не нравится мне, что у 1С конструктор массива не умеет сразу пихнуть в него нужные данные, как это есть для структуры. И что? Я могу поизвращаться, но большинство прикола не поймёт и право будет.
Да, я до сих пор не понимаю, зачем нужны отдельные операторы цикла. Та же логика, та же степень сложности написания, только ещё ограничений больше. Мне хватало goto/gosub и всяких прочих. А цикл... То шаг жёстко задан, то направление, то надо учитывать, с последней итерацией он или нет, то пост-условие нормально не пропишешь, то значение итератора не трожь, ибо сглючит... Ну нафиг.
Имхо, половина утверждений о кошмарности таких подходов базируется на неумении их правильно готовить.
Настоятельно советую вам, без обид, поработать над восприятием действительности, а не мнимых представлений о словах и действиях окружающих. А то, знаете, я вам пишу "а", а вы видите "б" и обобщаете уже вовсе некорректно)
Лично я применяю подобный подход в рекурсивных обработках деревьев и прочих подобных конструкций (допустим, десереализованных структур и соответствий из JSON - а как их еще обрабатывать?), когда терминальное условие задается кодом, также кодом задается эффективное вычисление. В итоге одна функция рекурсивного обхода решает множество подобных задач.
Вообще, умные существа это все придумали для того, чтобы максимальное количество кода использовалось повторно, чтобы костыли и велосипеды были максимально управляемы и имели минимальное количество экземпляров, ожидая, когда же придет архитектор, который положит конец этому конкретному костылю и велосипеду.
В общем, афтор, не обращай внимание на 1С-негов, которые наколотили тебе минусов - это проблема старения профессии, ибо даже в 35 лет уже становится сложно учиться, тем более ближе к полтиннику, а куча "матерых" 1с-негов уже дышат в эту отметку, а кто-то ее даже преодолел.
ЗЫ: на днях столкнулся с челом, который топил за обычные формы (меня только от привязок этих передергивает), при этом не мог обойти структуру, сериализованнуи из JSON и попросил вытащить ее в дерево. Я после этого понял, на сколько может быть 1С-нег примитивен в своем разумении. А чел конфы с нуля пишет, не понимаю только, почему он их на 8-ке рисует, а не на 7.7 - там то вообще всех этих проблем не было)))
В действительности, 99% рекурсивных функций весьма неглубокие - ну максимум 10 (тот же обход каталогов или групп товаров).
С другой стороны, что такое время? Я, конечно, много писал на 1С того, чему стоило бы работать как можно быстрее, но ускорить можно не только количеством строк, но и алгоритмом. Вот, например, недействительные паспорта. Можно загрузить их в БД для проверки - в 1С-ный регистр сведений загрузка легко займет 10 часов (если многопоточно, то пять, т.к. после загрузки в регистр 20кк записей параллельная запись будет сталкиваться с огромным количеством взаимных блокировок даже на очень хорошем железе). Если же просто в файлы с номером серии выгрузить список номеров - это уже 40 минут. При том проверка вместо минуты займет три, но мы же сэкономили 9 часов времени - можем три минуты подождать. А если вспомнить дискретную математику, то загрузка начинает занимать 10 минут, проверка - пару секунд. И ни одна таблица СУБД не пострадает от этой одноразовой информации, ибо все дело в алгоритме (на С загрузка файла без разархивации занимает вообще 2 секунды - сравните с 10-ю минутами на 1С в одну строку).
В общем, если ищите скорости - 1С тут нервно курит в углу даже по сравнению с Питоном. При том в Питоне итератор по генератору работает быстрее, чем обычный цикл (т.е. "For i in range(1,1000)" работает быстрее, чем "For (i=0;i<1000;i++)" ), но кому это интересно, да?
Анонимные функции не связаны с ООП. Если они затрудняют работу со "сложными расчетами", то с простыми - могут упрощать. И т.д.
Может быть вместо ForEach и Filter использовать русские названия? ДляКаждого , Фильтр и т.д.?
Исключительно ради уменьшения необходимости переключения раскладки
Грустно, что энтузиазм автора оценивается как призыв делать всё через анонимные функции. Может лучше подумать, а как вообще возникли такие идеи у человека, ограниченного языком платформы? Неужели всё так просто, и это только желание автора реализовать любимое ООП в платформе? Мне кажется, для того, чтобы начать это придумывать всегда нужен какой-то дополнительный толчок, что-то, что мешает полностью принять ограничения платформы.
Сомневаюсь, что в процентном соотношении тех, кто знает почему платформа устроена именно так и без ООП наберется хотя бы пятая часть.
Однако, хочу отметить, что хоть автор и думает о реализации ООП, средства, которые он реализует, по большей части есть средства функционального программирования.
Давайте на время забудем про рекомендации по методике разработки. Автор предлагает воспользоваться одними из самых мощных на сегодняшний день концепций разработки, в силу известных причин, не реализованных в платформе напрямую.
Эти концепции: Closure (лямбда-прототипы их основа), For_Each, Filter, Map, Reduce.
Хорошая корректная реализация этих концепций используется в масштабируемых распределенных вычислениях. Ведущие ИТ-компании сделали ставку на эти концепции и не прогадали.
Да, в рамках простого сопровождения, или написания рутинного кода отчетов и обработок такие инструменты могут выглядеть избыточно и монстроузно. Реализация этих концепций средствами платформы получается перегруженной кодом компиляции и т.п., но это работает.
Думаю, что простое знание того, что такие инструменты могут быть реализованы средствами платформы, и понимание спектра задач, которые стоит в рамках платформы решать такими средствами позволяет четче планировать архитектуру будущего приложения.
И заметьте, это я еще нигде не говорил о том, что это реально стоит применять. (Фактическое применение методик из статьи автора действительно должно быть обоснованно)
Однако умение представлять решение в терминах таких концепций позволяет на начальных этапах проектирования видеть, какие возможности приложения не укладываются в эти концепции и заранее принять меры по обеспечению масштабируемости.
Лично у меня случился некий качественный скачок мыслей, который и побудил меня высказаться:
На входе - статья автора с рабочим примером, с конкретикой, в которую обычно упирается мышление человека, привыкшего к декларативному программированию, и незнакомого или поверхностно знакомого с функциональным. (Это реальный барьер, мне известны разработчики, которые ну никак не могут принять идеи функционального программирования)
На выходе - идеи, как организовать проектирование новых решений.
Возможно я недостаточно понятно перешел от статьи автора к концепциям функционального программирования и от них к масштабируемости, но тут кратко изложить не получится. Может лучше получится объяснить ход моих мыслей если посмотреть описания файловых систем Hadoop и Google File System, где связка map-reduce является существенной частью системы.
Вы можете возразить, что указанные файловые системы далеки от задач, решаемых (в общей массе) в системах учета компаний, использующих решения на платформе "1С: Предприятие".
Соглашусь - далеки. Но дело не в самом перечне задач, а в методике проектирования решения. Если ваше решение легко формулируется в рамках map-reduce, то все, что лежит ниже уровня реализации map-reduce можно считать черным ящиком, а все, что выше может быть реализовано в масштабируемой гетерогенной среде, главным требованием которой являются только одинаковое понимание map-reduce частями системы. И тогда проектируемое решение уже точно становится масштабируемым до уровня вышеозначенных файловых систем, а это ценное преимущество.
Это лирика. Мое предложение автору такое: можно реализовать оптимизацию выполнения кода за счет кэширования. Для каждого исходного текста можно построить маркировку быстрыми ключами. Аналогичную маркировку для откомпилированного текста. Кроме того, завести дерево включения кода (когда в компилируемом коде тоже находятся объявления лямбд и т.д. в глубину). Это даст возможность осуществлять перекомпиляцию исходного текста только тогда, когда на этапе выполнения какой-то блок внутри кода был динамически перестроен.
Если к этому добавить менеджер контекста и стек возврата, то можно будет использовать оптимизацию выполнения итераторов за счет разворачивания хвостовой рекурсии в плоские циклы, что дает защиту от переполнения стека и существенное ускорение выполнения кода, поскольку основной код всегда будет выполняться циклом до опустошения стека возврата (вернее до опустошения менеджера контекстов).
PS. Первое применение для такого механизма я увидел в реализации универсального кода доступа к данным по структуре метаданных. Т.е., например, на входе таблица регистра, и набор полей и индивидуальных условий, по которым необходимо сложным образом отфильтровать данные. Можно построить такие лямбда-выражения, которые позволят формировать текст запроса к специфическим полям регистра. Причем у лямбд, генерирующих запрос к полю регистра на входе лямбды условий отбора. Может получиться красивый инструмент с визуальным конструктором, значительно ускоряющий разработку запросов.
Основная же цель, как я сейчас вижу - динамическая загрузка текстовых модулей или отдельных функций с возможностью автоматического получения их обновленных версий из репозитория (например, с github). Тут, конечно, не обойтись без компилятора со стеком. Им я и занимаюсь в свободное время.
А при наличии компилятора можно даже улучшить синтаксис и семантику языка 1С. Вплоть до того, чтобы программисты смогли писать на чем-то близком к javascript или python в системе 1с. Это полезнее, чем выносить примитивный язык 1С вовне.
Но вот динамическая загрузка текстовых модулей, генерация штатного исполняемого кода по неким правилам может существенно упроститься от ввода предложенных конструкций. Несколько лет назад я реализовал подобный проект в рамках коммерческого решения, и он до сих пор успешно работает, и сокращает время выполнения алгоритмов за счет генерации эквивалентного плоского кода взамен рекурсивного. Т.е. на входе алгоритм в виде рекурсивных функций, а на выходе циклический с разверткой хвостовой рекурсии. Там очень активно используется Выполнить() и Вычислить(), и за счет ухода от рекурсии и вложенных запросов было достигнуто ускорение 100х и линейная зависимость от объема входных данных вместо экспоненциальной. Заказчик готов мириться с любыми сложностями в поддержке этого продукта за достигнутое ускорение и гибкость настройки. К сожалению публиковать его не могу, т.к. такой был уговор с заказчиком.
Если без подробностей, то там я анализирую код функций/процедур с рекурсивными вызовами, выделяю циклы и условные операторы, и те конструкции, которые содержат внутри себя вызовы других процедур или функций из определенного перечня преобразую в линейный код с метками, для прохода по коду в состоянии ДО вызова вложенной процедуры/ и, соответственно, после.. Развернутый код посещается циклом управления дважды для каждого вложенного вызова, один раз с признаком подготовки вложенного вызова, другой с признаком подготовки возврата из вложенного вызова. Этапы подготовки заменяются на помещение в стек нового контекста в рамках того же цикла управления. А возврат - освобождение стека и заполнение данными возврата переменной вызывающего контекста, если это была функция с присваиванием. Дальше происходит магия, когда строится суперпозиция всех полученных таким образом циклов управления в одну общую конструкцию. Тут без дерева разбора никак.
Т.е. по сути строится автомат плоского циклического алгоритма эквивалентного рекурсивному и затем превращается в код 1С. А дальше получается готовый код функции. Этот код мы уже тестируем и помещаем в продакшн. Но и он в процессе работы динамически подгружает линейные участки в зависимости от настроек выполнения.
Этот пример я привел к тому, что в нем активно используется аналог предложенного вами решения, но только для генерации текста модулей и для выполнения плоских вставок заказчика.
Но планирую переделать на плоский код с метками и стеком, чтобы были разные точки входа в API модуля. Насколько я понимаю от классических циклов тоже придётся избавиться, потому что в них нельзя переместить курсор выполнения программы.
Разумеется, принципиально можно обойтись и без лямбд, тем более, реализованных на том же языке. Но также принципиально можно обойтись и без таблиц значений, однако их наличие в ряде случаев помогает решать некоторые задачи значительно проще, чем без таблиц. Примеры использования лямбд, как объектов первого класса приведены в статье. Но данную реализацию я сам не использую в работе и другим не рекомендую.
Рейтинг: 50
Вы можете заказать платную консультацию или разработку у автора. Будет создан приватный заказ на «Бирже заказов» для автора.
№ 1465926
Создание 28.06.21 11:00
Обновление 28.06.21 11:00
Просмотры 15533
Загрузки 37
Рейтинг
28
Комментарии 307
Код открыт Да
Рубрики Универсальные функции
Кому Разработчик
Тип файла Внешняя обработка (ert,epf)
Платформа Не имеет значения
Конфигурация Универсальные
Операционная система Не имеет значения
Страна Не имеет значения
Отрасль Не имеет значения
Налоги Не имеет значения
Вид учета Не имеет значения
Доступ к файлу Бесплатно (free)