Pull to refresh

Comments 431

Фреймворки становятся лучше, языки немного умнее, но в основном мы делаем то же самое.

Не из того же самого уже достаточно давно есть Haskell
Если цель просто не делать тоже самое, то есть brainfuck. Чего уж там :)
В brainfuck-е ничего оригинального нет, он просто предельно примитивен. О нём бы давно забыли, если бы не матерное название. Настоящий «brain fuck» это именно Haskell.
вобщета brainfuck — это машина тьюринга(с парой лишних операций)
Настоящие brainfuck — это APL/K/J и FP.
Haskell вполне понятныя язык.
Сам то он понятный, мозг выносит от того что на нём пишут гранды. С продолжениями, расширениями языка и многоэтажными преобразователями типов. Например dsl-hdl-и на нём, ClaSH в частности. (Что характерно, Chisel почему-то пользуется большей популярностью).
Clash и Lava ориентированы на схемы с одним тактовым сигналом. Это делает их достаточно простыми, но не всегда применимыми. Модель Chisel ближе к обычным HDL, с процессами реагирующими на изменения сигналов.
Мне кажется, человеку со стороны, не знакомому с HDL, проще будет освоить Clash, но для иинженеров ил микроэлектронной индустрии Chisel понятнее и мощнее.
Да бог с ними, с клоками. Я вот это хотел на Clash переложить, и сразу упёрся в запрет рекурсивных описаний, а это для моей древовидной структуры очень нужно. Даже на SystemVerilog-е как-то получилось, а тут нет!
Функциональный стиль существует где-то с 1960-го года. Всё то же самое…

Как тут с кейс-сенситивностью (она же чуыствительность к регистру)? А то в примерах ключевые слова полностью заглавными, остальное — не очень заглавными, как-то неоднородно выглядит

Язык полностью CASE-sensitive, в том числе ключевые слова. И они именно большими буквами, так как много ключевых слов, и если бы они были маленькими, было бы невозможно использовать в именах кучу распространенных слов (например, sum, group, in и т.п.) Ну и в блокноте проще читать такой текст.
Ну то есть в результате половина кода будет набрана КАПСОМ. Это было понятно, когда сиквел только зарождался и не было подсветки кода, но зачем это делать сейчас?
Ключевые слова в языке пишутся большими буквами, потому что их много, и потому что часть из этих ключевых слов — это вполне обычные английские слова. Если сделать их маленькими буквами, то мы не сможем именовать элементы (классы, свойства, формы, и т.д.) в системе этими словами.

Другой вопрос, почему их так много. Начнем с инструкций языка, которые в основном являются объявлениями некоторых элементов системы, их относительно много, и эти объявления необходимо как-то синтаксически разделять. Разделены они по факту в основном ключевыми словами (CLASS, FORM, CONSTRAINT, etc), идущими в начале объявления. Кроме этого (и что более важно) свойства и действия у нас бывают разных типов и создаются с помощью операторов. Типов много, операторов соответственно тоже, их тоже нужно как-то синтаксически разделять. Можно разделять их, например, некими конструкциями из спецсимволов, как, например, разделяются между собой (и у нас естественно тоже) арифметические, логические, битовые операторы, а можно ключевыми словами. Мы выбрали второй вариант, который, как нам казалось, был более читаемым и понятным потенциальным разработчикам с не очень большим техническим бэкграундом (ну и проводил какие-то параллели с sql). Да, выглядит несколько олдово, но, как мне кажется, это дело привычки. Тем более с поддержкой IDE набирать этот код не так неудобно, как кажется на первый взгляд.
на всякий случай — я не минусую Ваши ответы. И в целом, как full time SQL разработчик, считаю инициативу очень полезной. К капсу я в основном «привязался» потому, что считаю, что SQL на самом деле лучший язык для работы с данными, но как все SQL-related языки программирования не развиваются с такой скоростью, как остальные ЯП. И неиспользование капса делает язык более читаемым -> более подходящим для, собственно, программирования.

В целом SQL как язык запросов довольно полный, но как язык программирования его можно было развить добавив возможностей, например, возможность работать с query как с first-class-citizen, то есть реально сделать тип данных query (что то наподобие C# iqueryable).
Но тогда и автодополнения не было. А сейчас можно писать код не нажимая ни shift ни caps lock, и при этом называть свойства sum. Меня если честно к примеру раздражает в java называть переменные aclass, благо в java ключевых слов — кот наплакал.

Но как я уже писал, видимо придется добавить режим с low-case ключевыми словами, раз это некоторых так раздражает.
Точно :)

А interface как правильно — interfaze?
Меня если честно к примеру раздражает в java называть переменные aclass, благо в java ключевых слов — кот наплакал

Я, честно, не понимаю, зачем называть переменную class.

А сейчас можно писать код не нажимая ни shift ни caps lock, и при этом называть свойства sum

Так проблемы с написанием кода нет, проблема у меня лично возникает с чтением кода. Код пишется 1 раз а читается миллион раз. И лично мне понимать код, наполовину написанный капсом, сложнее, чем код, написанный лоу кейсом.
Дело вкуса, мне и сейчас в последней SQL Server Management Studio, несмотря на подсветку и автоподстановку, удобно в запросах ключевые слова писать капсом, перечитывать и разбирать проще. (но писать полноценные приложения в таком стиле не стал бы)
Тут ключевые слова большими как SQL. А классы и свойства — как в Java классы и методы.
в sql ключевые слова можно любым регистром писать.
заглавными — не более, чем рекомендация.
Да, но тут так пришлось сделать, чтобы упрости грамматику. Иначе синтаксис в других местах был бы более сложный. К тому же, часто бывает лучше рекомендацию сделать обязательной, чтобы код был однотипным.
Какие проекты сейчас пишут с использованием данного языка и кто?
Тут есть часть решений, которые сейчас в продакшне.

Ключевой продукт на языке сейчас — это ERP (на нем сейчас работает около половины из ТОП-10 розничных сетей Беларуси, несколько заводов и оптовиков). Все компании из разных отраслей и размеров, благо модульность позволяет как из кубиков собирать решение и для маленького магазина секонд-хенд и для FMCG сети (в тексте статьи про это было)

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

Плюс всякие внутренние проекты вроде CRM и т.п.

Для всех этих проектов в основном используем людей indoor, причем практически все без минимального / с минимальным IT бэкграундом (это дает реально большое количество плюсов). Но есть ряд проектов, где доработки идут сторонними разработчиками (как заказчика так и третьих лиц)

Правда тут надо понимать, что мы специально тормозили процесс использования языка, чтобы сохранить максимальный контроль за кодовой базой. Это позволяло изменять язык не оглядываясь на обратную совместимость, даже несмотря что первые проекты начали внедряться 8 лет назад. Сейчас конечно, так уже не получится, но мы довели его как раз до того состояния, где функционал в основном будет добавляться, а не изменяться, поэтому и сделали первый long-term backward-compatibility релиз.
в глобальной перспективе lsFusion под силу полностью заменить ERP, RAD и SQL платформы, которые lsFusion превосходит по всем нефункциональным требованиям

Гм. Чтобы потеснить платформу, нужно предоставлять то, что делает платформа. ERP-платформа — это, в том числе, пользовательский интерфейс, механизмы безопасности и интеграции, и все это с учетом расширяемости и настройки, в идеале — конечным пользователем. А вы говорите именно о языке.

В этом языке есть в том числе и функции платформы (все что вы говорите). Это будет в следующих статьях. Хотя уже сейчас можете зайти на сайт и посмотреть / попробовать онлайн как это выглядит. Вся документация с примерами, how-to и т.п. есть.

Но платформа вся полностью language-based. Поэтому речь идет о ней как о языке. То есть как с Java говорим партия, подразумеваем ленин, говорим язык, подразумеваем платформа и наоборот.
В этом языке есть в том числе и функции платформы (все что вы говорите).

Хм. Я даже перечитал два раза, чтобы быть уверенным, что там это написано: "в языке есть [...] все, что вы говорите". То есть в языке есть механизмы интеграции.


Можно пример того, как в вашем языке (нет, не в библиотеке, нет, не в платформе) сделан REST API?


Хотя уже сейчас можете зайти на сайт и посмотреть / попробовать онлайн как это выглядит.

Я вот сходил по вашей ссылке на ERP, и первый попавшийся мне файл — он на Java. И, кстати, никакой документации, никаких примеров, никакого how to, вообще ничего.

Вот я про это и говорю: это не в языке. Это вы на языке написали какой-то код, который что-то делает. Я такое могу написать, скажем, на C#, и это все еще не будет иметь отношения к платформе.


А платформа — это когда у вас есть в системе сущность Country, и она доступна по униформному протоколу по адресу https://вашаерп/api/Countries, а если пользователь накатил на систему расширение, которое в это Country добавляет новое свойство ISOCode, то оно автоматически отобразилось в API (и да, у вас к этому всему сразу доступны машинно-читаемые описания, по которым можно сгенерить клиента на любом языке).


В вашем случае функция платформы ограничивается тем, что вы автоматически выставляете свойство из модуля по фиксированному HTTP-адресу. Вы не делаете автоматического преобразования тела (ни на вход, ни на выход), там нет возможности управлять заголовками и кодами, и так далее, далее, далее. Для высокоуровневого — слишком много кода, для низкоуровневого — слишком мало контроля.

В вашем случае функция платформы ограничивается тем, что вы автоматически выставляете свойство из модуля по фиксированному HTTP-адресу. Вы не делаете автоматического преобразования тела (ни на вход, ни на выход), там нет возможности управлять заголовками и кодами, и так далее, далее, далее. Для высокоуровневого — слишком много кода, для низкоуровневого — слишком мало контроля.


Там есть все функции по управлению заголовками и кодами причем в обе стороны. Например свойство headers (ЕМНИП) при обращении из внешней системы, и HEADERS clause в операторе EXTERNAL (в примерах добавим в ближайшее время), в обратную сторону все тоже самое с именем headersTo. И этого хватало, к примеру, для интеграции с ЭСЧФ (без единой строки Java кода), а поверьте там очень жесткая интеграция (один только правильный порядок тегов в XML чего стоит).

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

В примере нет. К сожалению, угадывать, что в системе есть, слишком сложно.


поверьте там очень жесткая интеграция (один только правильный порядок тегов в XML чего стоит).

Гм, это то, что любой уважающий себя кодогенератор делает прямо по XSD? Или вам XSD не дали?


На остальное ответил ниже.

Про машинно-читаемое описание? Про no-code операции для объявленных в системе бизнес-сущностей?


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

В примере нет. К сожалению, угадывать, что в системе есть, слишком сложно.

Забавно, но про пример с HEADERS мне писали 3 дня назад, но как-то не успели его добавить. Извиняюсь, лишим человека который писал How-to премии, договорились? :)
Гм, это то, что любой уважающий себя кодогенератор делает прямо по XSD? Или вам XSD не дали?

Я просто в качестве примера привел, что разработчики этого сервиса не сильно заморачивались простотой этого интерфейса, но например генерация headers для аутентификации делается средствами языка.
Про машинно-читаемое описание? Про no-code операции для объявленных в системе бизнес-сущностей?
Как бы окей, да, вы дали низкоуровневый механизм, вы говорите, что в нем есть все средства контроля над протоколом, я вам поверю. Этим механизмом вы соревнуетесь с кучей существующих сервисных фреймворков, и я не думаю, что вы победите. А чтобы играть на поле платформ, вам нужны решения, которые предоставляют API внешним потребителям без единой дополнительной строчки кода.

Про машинно-читаемое описание, честно говоря совсем не понимаю, что вы имеете ввиду.
No-code операции для объявленных в системе бизнес-сущностей, есть много в том числе такие, которых у других принципиально быть не может, например вы можете для ЛЮБОГО показателя на форме, в том числе вычисляемого (!) включить логирование. Да это наверное часть платформы, а не языка (тут да в коментарии ниже забыл добавить, что искать не language-based возможности кроме раздела управление)
Про машинно-читаемое описание, честно говоря совсем не понимаю, что вы имеете ввиду.

Я имею в виду приблизительно вот так: https://вашаерп/api/Countries?wsdl — получаем готовый WSDL, который можно скормить любому совместимому инструменту и получить готовый SOAP-клиент, аналогично для OpenAPI и REST-клиентов.


генерация headers для аутентификации делается средствами языка.

Если мы говорим про "написать на языке программирования формирование заголовков запроса", то удивительно, что вы вообще считаете нужным об этом упоминать. Вот если бы у вас средствами платформы было автоматическое обновление OAuth-токенов для систем, к которым вы обращаетесь (и автоматическая подстановка этих токенов в запросы) — это да, повод для гордости.


No-code операции для объявленных в системе бизнес-сущностей, есть много

Я пока про API говорил. Банальный автоматический REST (а лучше — OData или GraphQL) или SOAP API для всех бизнес-сущностей в системе.


в том числе такие, которых у других принципиально быть не может

… у других кого? Платформ? Ну, я бы не был на вашем месте так уверен, платформы разные бывают.

Я имею в виду приблизительно вот так: вашаерп/api/Countries?wsdl — получаем готовый WSL, который можно скормить любому совместимому инструменту и получить готовый SOAP-клиент, аналогично для OpenAPI и REST-клиентов.

Ну если честно, пока именно генерацию WSDL мы пока не делали. Тут важно что: интеграция в lsFusion разделена на две части, первое непосредственно обращение с передачей данных (как примитивов, так и XML и JSON) по сетевому протоколу, например, HTTP, а второе разбор переданных данных (чтение из XML, JSON в поля, свойства и т.п.). Соответственно за вторую часть (разбор данных) отвечают формы (это универсальный механизм и для отчетов и для экспортов/импортов и для интерактивных форм) и по сути они являются спецификацией для обмена. Да можно сделать конвертер Формы<->WSDL (а точнее генерацию формы по WSDL и наоборот), но в последнее время куда чаще сталкиваемся JSON Api, так что генерация формы по JSON пока актуальнее :) Но согласен задача важная хоть и не критичная, думаю сделаем в ближайшей версии (вот прямо сейчас начали :) )
Вот если бы у вас средствами платформы было автоматическое обновление OAuth-токенов для систем, к которым вы обращаетесь (и автоматическая подстановка этих токенов в запросы) — это да, повод для гордости.

Компилятор с универсальным predicate-pushdown (а не с частными случаями как в современных СУБД), пессимистичный cost-based планировщик (который не получает в середине плана 1 и сваливается в nested loop двух 10 тысячных таблиц), архитектура, в которой можно в любой момент откатить запрос \ транзакцию и начать ее заново, когда компилятор ошибся или произошел update conflict, и абсолютная реактивность везде (например материализации любых показателей в одно слово без ограничений) — это повод для гордости. А обновление OAuth-токен — это просто фича, которая в задачах ERP-платформ, с которых вы начали спор, не очень то нужна.
Я пока про API говорил. Банальный автоматический REST (а лучше — OData или GraphQL) или SOAP API для всех бизнес-сущностей в системе.

Я же вроде сверху писал про REST Api. Но в любом случае предлагаю дождаться третьей статьи там все будет. А то я ее тут уже по сути начал писать.
… у других кого? Платформ? Ну, я бы не был на вашем месте так уверен, платформы разные бывают.

Для того чтобы это сделать нужно поддержать полную инкрементальность (реактивность) по данным, что является очень сложной архитектурной задачей (я в тексте статьи кидал ссылки, что у Oracle и Microsoft получилось в одном частном случае — обновляемых материализованных представлениях). Так что, если вы не уверены, приведите пример.
Соответственно за вторую часть (разбор данных) отвечают формы

И почему-то мне кажется, что все приведенные ради примеры — это не так, а совсем иначе.


А обновление OAuth-токен — это просто фича, которая в задачах ERP-платформ, с которых вы начали спор, не очень то нужна.

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


Для того чтобы это сделать нужно поддержать полную инкрементальность (реактивность) по данным

Я боюсь, что у вас может быть свое представление того, что считать "логгированием".


что является очень сложной архитектурной задачей

Паттерн Event Sourcing.

И почему-то мне кажется, что все приведенные ради примеры — это не так, а совсем иначе.

В языке есть shortcut для импортов из плоских форматов, когда форму не надо создавать (она создается неявно). Собственно они в примере и используются. Вы лучше пример в попробовать онлайн или обращении из внешней системы посмотрите.
Эм. Она как раз очень нужна, потому что современные платформы постоянно интегрируются с кем-то. Я, собственно, несколько лет только интеграционными задачами и занимался.

В этом смысле современный мир достаточно забавен. Платформы постоянно интегрируются с фейсбуками, а когда человек стоит в банке и выполняет какую-то простейшую операцию, при этом операторша такое ощущение набирает войну и мир, никого не волнует. Точнее не так, они считают что это криво, но что поделаешь. Так вот поделать можно много чего, просто в этом винигрете из ORM, SQL, Reporting systems, и т.п. тяжело что-то сделать. Даже с нуля.
Собственно вы несколько лет только интеграционными задачами занимались, а мы последние n-лет разгребали конюшни из Дельфи/Ораклов, Аксапт, 1Ск, Аксессов и кучу чего еще. И поверьте там все далеко не так хорошо, раз их владельцы решили их поменять.
Я боюсь, что у вас может быть свое представление того, что считать «логгированием».

Смотрите вы видите, на форме какой нибудь показатель, не знаю, например в скольки ассортиментных матрицах учавствует товар. Этот показатель считается каким-то сложным способом (как хватило фантазии разработчика, заказчика). На нижнем уровне это естественно должно выполняться в SQL потому как иначе в FMCG сети с их объемами все естественно ляжет (но это детали разработчик и пользователь этого не видят / не знают). И дальше пользователь решил, а давайте я его буду логировать. Он жмет правую кнопку и выбирает логировать. После этого он может нажать правую кнопку и просмотреть когда и кем это свойство изменялось (еще раз оно не хранится, а вычисляется, в том числе с импользованием десятка таблиц). Причем оно может изменяться в куче сценариев, товар перенесли между матрицами, матрицы перепривязали к другим матрицам и т.п. Все эти сценарии выполняют разные люди / написаны разными разработчиками, которые вообще не знают ни про какое логирование, ни про существование формы с этим показателем, ни даже о существовании самого показателя.

На самом деле, чтобы реализовать это эффективно, нужно сделать механизмы инкрементального обновления каждого типа оператора (скажем GROUP SUM, (+) и RECURSION инкрементируются очень хорошо, композиции так себе, PARTITION ORDER терпимо), затем нужен компилятор запросов с эффективным predicate push down (не колонка-колонка как в Oracle и MSSQL а в общем случае с UNION'ами, с группировкой внешнего контекста и т.п.), с материализацией подзапросов (все СУБД офигенные оптимисты и очень любят косячить со статистикой и estimate'ть 1 row, после чего nested loop может угрохать сервер), правильное разбиение логического условия на условие запроса и тип join'а (зачем SQL разделил логику отборов в типы JOIN'ов и WHERE, а просто не сделал скажем чтобы для FULL JOIN можно было писать WHERE IN JOIN a OR IN JOIN b — загадка), а это нужно делать с учетом статистики и там еще с десяток таких оптимизаций. И без каждой из этих оптимизаций никуда, проверено практикой и разборками с заказчиками. И вы не скажете разработчику сказать, ты не правильно сделал запрос, он вообще не в курсе, что такое SQL. И сделать так чтобы все это работало из коробки на больших объемах поверьте очень сложная задача. И именно на нее ушло целых 12 лет.
Платформы постоянно интегрируются с фейсбуками

Не с фейсбуками, а с е-коммерсом, складскими платформами, соседним CRM и еще миллионом вещей, которые бизнес использует для своей работы.


Собственно вы несколько лет только интеграционными задачами занимались, а мы последние n-лет разгребали конюшни из Дельфи/Ораклов, Аксапт, 1Ск, Аксессов и кучу чего еще.

Вы не одиноки в этом разгребании.


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

Гм. Вы только что ввели невозможный набор ограничений, потому что есть расчеты, которые невозможно (или избыточно сложно) сделать в SQL.


И сделать так чтобы все это работало из коробки на больших объемах поверьте очень сложная задача

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

Гм. Вы только что ввели невозможный набор ограничений, потому что есть расчеты, которые невозможно (или избыточно сложно) сделать в SQL.

В SQL да, а в более высокоуровневых операторах (группировка, разбиение и рекурсия) без проблем.
Поверю. Невозможная. Поэтому я не верю, что вы ее решили в полном объеме — скорее что вы выбрали набор (вполне разумных) ограничений, в рамках которых вы ее решили, а для всех остальных случаев добавили какие-то (вполне разумные) заглушки.

Вот уже близко к сути подошли. Я понимаю, что не верите, я честно говоря сам по началу заходил к клиентам, и бродил по формам, просто наблюдая как все работает, понимая какая махина крутится внутри. Ощущение как на самолете летишь, как такая бандура из железа вообще может быть в воздухе :).
Явных ограничений нет, в некоторых случаях может потребоваться оптимизация производительности, но там как в самолете (не тот который индусами по 9 долларов в час, а в идеальном), каждый верхний оптимизатор подстраховывает нижний, поэтому такие случаи если и возникают то при стечении большого количества разных факторов.
То есть, к примеру, те же материализации разработчики расставляют по джедайски, IDE подсказывает приблизительную сложность (то есть как далеко до следующих материализованных показателей), а материализуем-ка это свойство. В том числе можно материализовать PARTITION и RECURSION (современные субд даже если в запросе подзапросы есть отказываются это делать, не говоря уже про такие сложные операторы, кстати забавно что RECURSION при этом на самом деле хорошо «инкрементится»).
В SQL да, а в более высокоуровневых операторах (группировка, разбиение и рекурсия) без проблем.

Вроде бы только что было ограничение "должно выполняться в SQL". Уже нет?


Явных ограничений нет

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

Вроде бы только что было ограничение «должно выполняться в SQL». Уже нет?

Тут видимо мы не допоняли друг друга. SQL вообще полон по тьюрингу, на нем можно любое вычисление реализовать. Я думал что речь шла о том, что есть вычисления, которые на SQL просто сложно задавать (настолько что это «невозможно» сделать). Соответственно написал, что на более высокоуровневых операторах (которые во всяком случае функциями а не таблицами оперируют) это куда проще.

Но выполняться естественно должно на SQL, иначе не вытянет по производительности.
Ну то есть, какую бы операцию я не решил вызвать, будет работать, будет работать за предсказуемое время, и будут сохраняться все ранее сделанные гарантии — например, будут видны все изменения данного значения, безотносительно того, заходили ли люди на форму, и время/причина изменения?

Да все чисто, нажал включить логирование, нажал правую кнопку увидел когда изменялся показатель и чье изменение к этому привело.

На самом деле там просто неявно создается свойство, событие и форма:
a(X x,Y y) = ...
logA = DATA (Session, X, Y) 
WHEN CHANGED(a(x,y)) DO
      logA(currentSession(), x, y) <- a(x,y);
FORM LogA
      OBJECTS x=X, y=Y PANEL
      OBJECTS s=Session
      PROPERTIES dateTime(s), user(s), logA(s,x,y)
;

Ну и на саму форму в которой включалось логирование неявно добавляется событие:
...
PROPERTIES a(x,y) ON SHORTCUT 'показать лог' {
     SHOW LogA OBJECTS x=x, y=y;
}
...

Но это я уже сильно забежал вперед.
SQL вообще полон по тьюрингу, на нем можно любое вычисление реализовать.

Но будет ли это эффективно?


Я думал что речь шла о том, что есть вычисления, которые на SQL просто сложно задавать

Нет, речь шла о том, что есть вычисления, которые на SQL делать неэффективно, а есть операции, которые вообще не вычисления.


Но выполняться естественно должно на SQL, иначе не вытянет по производительности.

Вы правда никогда не видели операций, которые быстрее делать не на SQL?


Да все чисто, нажал включить логирование, нажал правую кнопку увидел когда изменялся показатель и чье изменение к этому привело.

Эмм. Вот представьте себе, что у вас показатель рассчитывается внешней системой; вызов веб-сервиса, который отдает вам некое значение в зависимости от других показателей на форме, и этот веб-сервис — не чистая функция. Как вы будете показывать, от чего зависит текущее значение?

Нет, речь шла о том, что есть вычисления, которые на SQL делать неэффективно, а есть операции, которые вообще не вычисления.

Ну я вел речь именно про вычисления. И практически все алгоритмически простые задачи решаются эффективно на SQL. Под алгоритмически простыми я имею ввиду, суммы, фильтры, разбиения и т.п., но их может быть просто много например штук 10 при расчете.
Вы правда никогда не видели операций, которые быстрее делать не на SQL?

Видел. Например задача коммивояжера. Но речь то не про такие операции, а про вычисления различных показателей в большинстве ИС / бизнес-приложений.
Эмм. Вот представьте себе, что у вас показатель рассчитывается внешней системой; вызов веб-сервиса, который отдает вам некое значение в зависимости от других показателей на форме, и этот веб-сервис — не чистая функция. Как вы будете показывать, от чего зависит текущее значение?

А я где-то писал про веб-сервис? Речь в примере шла только про данные внутри системы.
И практически все алгоритмически простые задачи решаются эффективно на SQL.

Вот, скажем, нахождение k ближних в n-мерном пространстве, да?


Под алгоритмически простыми я имею ввиду, суммы, фильтры, разбиения
[...]
Но речь то не про такие операции, а про вычисления различных показателей в большинстве ИС

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


А я где-то писал про веб-сервис?

Я специально спрашивал: "какую бы операцию я не решил вызвать". Вызов веб-сервиса, вроде как, полновправная операция в вашем языке, мне это совсем недавно рассказывали.


Речь в примере шла только про данные внутри системы.

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

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

Ну на балалайке платформа тоже играть не умеет. Давайте так, например, в ERP-системах описанных задач штук 5. При этом «обычных» задач / показателей без вывертов тысяч 40. Тут не то что правило Парето нарушается, тут оно даже близко не стояло.
Я специально спрашивал: «какую бы операцию я не решил вызвать». Вызов веб-сервиса, вроде как, полновправная операция в вашем языке, мне это совсем недавно рассказывали.

Это логика действий, а речь опять таки шла о вычислениях. Но любых вычислениях, вообще любых. Понятно, что погоду она предсказывать не умеет, если вы это имеете ввиду под «разумными ограничениями», ok, пусть будет так. Хотя тут становится интересно, а ограничения в Oracle и MSSQL на материализованные обновляемые представления в статье — разумные?
Давайте так, например, в ERP-системах описанных задач штук 5.

… и эти 5 в какой-то момент могут стать market differentiator.


Это логика действий, а речь опять таки шла о вычислениях.

У вас было написано:


"Этот показатель считается каким-то сложным способом (как хватило фантазии разработчика, заказчика)."


И я явно переспросил: какую бы операцию. Вызов веб-сервиса для расчета чего-то в нынешнем мире — вполне себе сложный (даже не такой уж и сложный) способ расчета.


Но любых вычислениях, вообще любых.

Выше уже выяснили, что не любых. Forward propagation по нейронной сети для получения классификатора по тексту? Мне почему-то кажется, что нет.


Я не спорю, что вы решили хорошую, красивую, сложную задачу. Я бы с ней не справился.

… и эти 5 в какой-то момент могут стать market differentiator.

В этом и ирония, операторша пишущая трехтомник при выполнении простейшей операции и очереди в кассу банка людей мало волнуют. А вот интеграция с фейсбук — это market differentiator. Но с другой стороны — селяви.
И я явно переспросил: какую бы операцию. Вызов веб-сервиса для расчета чего-то в нынешнем мире — вполне себе сложный (даже не такой уж и сложный) способ расчета.

Помните в КВН очень старый номер детей лейтенанта Шмидта с «падлавил». Ок, вы опять выиграли :)
В этом и ирония, операторша пишущая трехтомник при выполнении простейшей операции и очереди в кассу банка людей мало волнуют. А вот интеграция с фейсбук — это market differentiator.

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


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

Не принимайте на свой счет. Я просто общаюсь в том числе с людьми из банковской сферы, и они так бодро расказывают как у них все классно, а когда им задаешь предметные вопросы про вполне бытовые вещи, они говорит да, криво, неудобно, но что поделаешь. И вместо того чтобы лечить болезнь, они начинают лечить симптомы, типа а давайте к 30 плохо работающим системам, прикрутим еще 31-ю, которая будет интегрировать эти 30 систем. В итоге получаем 31 плохо работающую систему. Они реально считают, что технический долг можно решить, добавляя сверху новые и новые костыли.
и первый попавшийся мне файл

Это потому, что буква «j» идет в английском раньше буквы «l». Вообще, там сейчас 323 файла Java (в основном legacy код, который появился до многих возможностей в самой платформе) и 2274 файла на lsFusion.
И, кстати, никакой документации, никаких примеров, никакого how to, вообще ничего

Просто ERP на ее базе — пока что коммерческий продукт. И это единственная в нем защита от несанкционированного распространения.
Не в ту ветку.
Можно пример того, как в вашем языке (нет, не в библиотеке, нет, не в платформе) сделан REST API?

Вот тут. Но это обращение к внешней системе. Что касается из внешней системы — любое действие можно вызвать из внешней системы при помощи http запроса. То есть фактически создание действия это и есть создание REST Api. Собственно у нас очень часто так и идет интеграция — создаем действие doSomething() {}, а тем кто интегрируется кидаем ссылку хттп://mysite.com/exec?action=doSomething. Хотя конечно если захотеть можно и тут придраться.
Я вот сходил по вашей ссылке на ERP, и первый попавшийся мне файл — он на Java

Ну как я уже писал первые проекты начали внедряться 8 лет назад, а механизмы интеграции появились года 3 назад. Честно говоря давно собирались их переделать, но тут решили не трогать то, что работает. А так, за последние 3 года в ERP хорошо если 500 строк кода на Java сделано, и то это работа с каким-то специфичным оборудованием, где уже есть готовые библиотеки.
И, кстати, никакой документации, никаких примеров, никакого how to, вообще ничего.

Документация, Примеры (в том числе в попробовать онлайн), How-to
любое действие можно вызвать из внешней системы при помощи http запроса

И это функция языка или платформы?


Хотя конечно если захотеть можно и тут придраться.

Да зачем придираться, достаточно одного простого пункта: как получить машинно-читаемое описание параметров и ответов вашего действия?

И это функция языка или платформы?

Давайте так, во-первых, прямо в языке есть функция интеграции (копия из документации по ссылке):

externalHTTP()  { 
    EXTERNAL HTTP GET 'https://www.cs.cmu.edu/~chuck/lennapg/len_std.jpg' TO exportFile; 
    open(exportFile()); 

    EXTERNAL HTTP 'http://tryonline.lsfusion.org/exec?action=getExamples' PARAMS JSONFILE('\{«mode»=1\}'TO exportFile; // фигурные скобки escape'ся так как используются в интернационализации
    IMPORT FROM exportFile() FIELDS () TEXT caption, TEXT code DO
        MESSAGE 'Example : ' + caption + ', code : ' + code;
        
    EXTERNAL HTTP 'http://tryonline.lsfusion.org/exec?action=doSomething&someprm=$1' BODYURL 'otherprm=$2&andonemore=$3' PARAMS 1,2,'3'// передает в BODY url-encoded второй и третий параметры
}
externalSQL ()  { 
    EXPORT TABLE FROM bc=barcode(Article a) WHERE name(a) LIKE '%Мясо%'// получаем все штрих-коды товаров с именем мясо
    EXTERNAL SQL 'jdbc:mysql://$1/test?user=root&password=' EXEC 'select price AS pc, articles.barcode AS brc from $2 x JOIN articles ON x.bc=articles.barcode' PARAMS 'localhost',exportFile() TO exportFile; // читаем цены для считанных штрих-кодов
    
    // для всех товаров с полученными штрих-кодами записываем цены
    LOCAL price = INTEGER (INTEGER);
    LOCAL barcode = STRING[30] (INTEGER);
    IMPORT FROM exportFile() TO price=pc,barcode=brc;
    FOR barcode(Article a) = barcode(INTEGER i) DO 
        price(a) <- price(i);
}

Во-вторых, еще раз это lsFusion это и язык и платформа. Точно так же как Java это и язык и платформа. Точнее даже не так, есть Java язык и Java платформа, точно так же есть и lsFusion язык и lsFusion платформа.
прямо в языке есть функция интеграции

… которая обеспечивает только вызовы наружу, но не входящие. Кстати, вы вообще разделяете язык и его стандартную библиотеку?


точно так же есть и lsFusion язык и lsFusion платформа.

Именно об этом я и говорю: чтобы заявлять "в глобальной перспективе lsFusion под силу полностью заменить ERP, RAD и SQL платформы", нужно говорить о платформе, а не о языке. А статья, насколько я ее смог прочитать, именно о языке.

… которая обеспечивает только вызовы наружу, но не входящие.

Да, но и средства интеграции прямо в языке тоже есть. Хотя ладно, немного глупый спор, будем считать, что вы выиграли :).
Кстати, вы вообще разделяете язык и его стандартную библиотеку?

Честно говоря, разделяли, первые лет 10. Но потом когда встал вопрос автоматизации всех процессов (а у нас почти все процессы автоматизированы до одной кнопки) возник вопрос целесообразности поддержки этой библиотеки отдельно. То есть для нее нужны отдельные версии, репозитарии, нужно постоянно переключаться между несколькими ветками и т.п… При этом выигрыш был непонятен, модульность обеспечивается другими средствами (REQUIRE модуль в заголовке), а экономить сто килобайт на сто мегабайтном файле смысла очень мало. Поэтому где-то 2 года назад решили долить большинство стандартных библиотек внутрь платформы, тем более что в платформе и так количество системных библиотек было сопоставимо с количеством этих стандартных библиотек.
Именно об этом я и говорю: чтобы заявлять «в глобальной перспективе lsFusion под силу полностью заменить ERP, RAD и SQL платформы», нужно говорить о платформе, а не о языке. А статья, насколько я ее смог прочитать, именно о языке.

Еще раз платформа практически полностью language-based. То что вы нашли одну фичу (обращение из внешней системы) не language-based, поздравляю, но вам очень повезет если найдете вторую (поверьте я участвовал в написании документации знаю о чем говорю). Плюс теоретически кто-то другой может запилить другую реализацию платформы построенной на этом языке, и что тогда? Вы же не придираетесь что Java как язык продвигают, а не как платформу.
Поэтому где-то 2 года назад решили долить большинство стандартных библиотек внутрь платформы, тем более что в платформе и так количество системных библиотек было сопоставимо с количеством этих стандартных библиотек.

Ну то есть единственный способ этим воспользоваться — это писать для одной платформы на одном языке. Хм.


Еще раз платформа практически полностью language-based.

Что вы понимаете под этим утверждением?


Вы же не придираетесь что Java как язык продвигают, а не как платформу.

А мне, собственно, все равно, потому что я знаю про существование Kotlin и Scala. А учитывая, что сам я пишу в основном для .net, где это разделение еще сильнее, мне все равно дважды.

Ну то есть единственный способ этим воспользоваться — это писать для одной платформы на одном языке. Хм.

Не совсем понял, о чем речь. Нет, можно писать и на Java и на Kotlin, если сильно понадобится, что мы кстати и делаем, собственно ссылку вы сами приводили выше. Подключается проще некуда f = INTERNAL 'my.class.action' и используйте как обычное действие. Наоборот все чуть сложнее, но поверьте это все равно куда проще чем в условном ORM. Ну и если надо DI, то сам сервер можно подключать через Spring Beans, и наоборот если в той же виртуальной машине нужен мини Java сервер (вроде оборудования как вы видели), его можно через Spring Beans подключить к серверу приложений.
Что вы понимаете под этим утверждением?

То есть любая абстракция системы задается кодом на этом языке (кроме дизайна отчетов там — xml, ну в будущем кастомизацию дизайна форм на react'е скорее всего подключим там будет javascript/react.
А учитывая, что сам я пишу в основном для .net, где это разделение еще сильнее, мне все равно дважды.

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

… а вот это утверждение намного скучнее оригинального, потому что понятно, что платформы, написанные на (каком-то) языке, могут конкурировать с другими платформами. Вопрос в том, как писать будут.

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

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

>> Он гораздо лучше оптимизируется

Когда сочиняли Хаскель, именно так и думали. Но потом «что-то пошло не так (с)».

>> само слово “свойство” короче, чем «чистая функция», плюс не имеет ненужных ассоциаций.

Зря вы заменили привычные названия на вам приятный новояз. Это мешает тем, кто знает о чём речь. Хотя да, обычно продвижение языков начинают с полностью некомпетентной части разработчиков, что даёт большое количество участников, но если при этом заранее исключать грамотных участников — вы быстро выйдете из моды, ибо некомпетентная часть очень скоро перескочит на очередной «тренд».

>> SQL большинство из них недолюбливают, слишком уж там много магии под капотом

Здесь опять уход в сторону примитива. Не «недолюбливают», а просто не понимают. Хотя опять же — повысить ЧСВ недостаточно грамотных разработчиков в рекламных целях — это работающий рекламный ход.

>> в глобальной перспективе lsFusion под силу полностью заменить ERP, RAD и SQL платформы

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

Конструктивно же — выход «на рынок» с новым инструментом есть дело затратное. Затраты, обычно, мало кто считает. Поэтому мало кто реально выходит на рынок.

Большие конторы, у которых денег немеряно, обычно продумывают стратегию использования новых инструментов. Сначала они спрашивают себя — а что мы можем поиметь с вывода на рынок вот такой вот тулзы? И просто некие абстрактные толпы поклонников в данном случае им мало интересны. Потому что им нужно окупить затраты на вывод системы в массы. А теперь сравним с вами — что вы намереваетесь получить? Если ответ привычный «много денег», то возникает вопрос — как? Вы думали? Сильно подозреваю, что нет. Точнее «в общих чертах мне всё понятно» как раз на самом деле является ответом типа «не думал». Бывает ещё ответ «хочу увидеть рост популярности моего любимого зайчика (инструмента)». Но здесь возникает второй вопрос — а вы знаете, сколько денег стоит вывести инструмент в разряд «популярных»? Подозреваю, что ответ опять — нет.

Ладно, это всё лирика, так, на будущее, может вас заинтересует.

По языку же скажу одно — заимствование давно известных подходов в новом инструменте никогда не являлось созданием нового подхода. Хотя да, для целей маркетинга и не такое подходит.

Новый язык должен дать нечто ранее не использованное в других языках. Ваша задача — указать это нечто и тем заманить массы в ваш лагерь. Из выше приведённого текста суть преимущества вашего языка не очевидна. В основе — функциональный подход, скрещенный с процедурным с надеждой на декларативность получившихся SQL-like конструкций. При этом основной нишей изначально была явно работа с БД, хотя в дальнейшем «Остапа понесло» и набор ниш быстро расширился. В целом получаем просто новый язык, который просто нравится автору, который считает, что создал нечто небывалое, а потому всем это будет интересно и все быстро станут это всё учить, использовать, ну и далее близится happy end.

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

А можно уточнить, при помощи каких платформ/технологий сейчас по-вашему можно быстро, качественно и дешево делать ERP продукты? Ну, чтобы было с чем сравнивать…
Для «по быстрому» — на тех, которые знает разработчик.

Для «качественно» — при помощи средств, позволяющих гибко оперировать абстракциями. Например — Java. Хотя и Java ещё есть куда расти.

Для автора же важно понять хотя бы одну область, где его детище окажется явно лучше других. Ну и показать эту область остальным.
Для «по быстрому» — на тех, которые знает разработчик.

Предположим разработчик ничего не знает, или хочет делать не «по быстрому», а надолго и всерьез.
Для «качественно» — при помощи средств, позволяющих гибко оперировать абстракциями. Например — Java. Хотя и Java ещё есть куда расти.

Вы всерьез предлагаете делать логику заказов/поставок/платежей на pure java? А еще же фронт надо будет писать.

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

Собственно мы сейчас и обсуждаем область — ERP системы. На данный момент, лидером в этой области (именно ERP-платформ) в РФ является 1С. Даже не касаясь всех его недостатков, у него как минимум есть один достаточно серьезный — он коммерческий. Предложите что-то другое, на чем можно делать продукт быстро, дешево и качественно.
И опять же речь идет не только о ERP. Допустим вам нужно написать какой-то простой процесс, но google docs уже недостаточно. Что Вы возьмете?
>> Вы всерьез предлагаете делать логику заказов/поставок/платежей на pure java?

Логика — это как раз pure язык ХХХ. То есть чистая логика (чистые алгоритмы) пишутся на чистых языках (без библиотек и прочего).

>> А еще же фронт надо будет писать.

Есть GWT.

>> Допустим вам нужно написать какой-то простой процесс

Простой обычно означает — надо дёшево и быстро. Поэтому просто использую то, что знаю.
Логика — это как раз pure язык ХХХ. То есть чистая логика (чистые алгоритмы) пишутся на чистых языках (без библиотек и прочего).

Хорошо, вот логика — есть миллион заказов, нужно посчитать их сумму. Как это сделать на pure языке XXX? Загрузите через ORM все в память? Или будет уже использовать не pure язык XXX, а pure язык YYY? Сколько в итоге языков надо знать, чтобы разработать простенькое приложение?
Как это сделать на pure языке XXX?

dbContext.Orders.Sum(o => o.Amount)

Это слишком простой случай. В более сложном на LINQ вы уже не сможете сделать. Но это и не важно. Приведите пример на не проприетарной технологии.
Это слишком простой случай.

Какой попросили.


В более сложном на LINQ вы уже не сможете сделать.

На LINQ — не смогу, смогу на чем-то другом.


Приведите пример на не проприетарной технологии.

А с чего бы вдруг такое ограничение?

Вообще говоря .net полностью опенсорсный и с более либеральной лицензией, чем у вас. Процитированный код можно выполнить вообще без единой строчки закрытого кода, если запускать на Linux против опенсорсной ДБ типа постгри.

Прошу прощения, давно не следил за LINQ. Майкрософт действительно в последнее время стал значительно более открыт к общественности. Подскажите, пожалуйста, а как LINQ сейчас запустить с PostgreSQL и Linux? Кто поддерживает?

Entity Framework Core запускается на Linux из коробки и поддерживается Microsoft. Провайдер для PostgreSql поддерживается сообществом, но вполне продакшн-реди

А можно ссылку на провайдер для PostgreSQL. А то у меня Google выдает ссылку только на коммерческие, а также те, которые уже не поддерживаются.
Кроме того, а что насчет IDE? Есть какая-нибудь бесплатная IDE для разработки на LINQ?
Кроме того, а что насчет IDE? Есть какая-нибудь бесплатная IDE

VS Code.

быстро, качественно и дешево делать ERP продукты?

Вы же помните про "вычеркните одно" (а лучше два)?

На одном и том же языке можно разрабатывать в нескольких стилях. При этом сумма стилей охватит все заявленные требования.

Не одновременно. Ну не выйдет обмануть этот треугольник.

UFO just landed and posted this here
Не существует абсолютных понятий «быстро», «качественно» и «дешево». Есть только быстрее, качественнее и дешевле. Так что тут все зависит от рынка. Если, например, на определенном рынке только 2 игрока и один лучше его по всем параметрам, то быстро, качественно и дешево возможно.
Если, например, на определенном рынке только 2 игрока и один лучше его по всем параметрам, то быстро, качественно и дешево возможно.

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

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

В плане «не одновременно» я согласен с комментарием выше — только до появления некоторого важного расширения, для которого вполне есть место.
Проблема в том, что заказчики, как правило, ничего не хотят вычеркивать. А маркетологи поставщиков всегда утверждают, что у них все три. И на заключении сделки все думают, что все будет так, как они считают.
Но мне было просто интересно, что же предлагает использовать автор комментария для этой цели.
Проблема в том, что заказчики, как правило, ничего не хотят вычеркивать

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


А маркетологи поставщиков всегда утверждают, что у них все три.

И врут. Не уподобляйтесь.

И врут. Не уподобляйтесь.

К сожалению, тогда проиграете. Много раз проходили. Вы говорите все честно, а конкуренты врут по-черному. В итоге заказчик выбирает конкурента, так как три больше двух.
Потом конечно матерится по-черному, но поезд ушел. У нас мало кто готов выбросить то, за что уже заплачены деньги.
К сожалению, тогда проиграете.

Или выиграете в долгосрочной репутационной перспективе. Это тоже работает.

>> выиграете в долгосрочной репутационной перспективе

Не могли бы вы представить примеры?

На мой взгляд репутации сегодня нет ни у кого. Хотя здесь можно поговорить о моём максимализме :)
Не могли бы вы представить примеры?

Я боюсь, что мой личный опыт работы с какими-то поставщиками услуг, которые честно говорили сроки, и придерживались (в противовес тем, которые говорили "завтра" и были посланы), вам ничего не скажет.


На мой взгляд репутации сегодня нет ни у кого.

Репутация есть у всех.

Зря вы заменили привычные названия на вам приятный новояз.

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

Поверьте 12 лет разрабатывать что-то на голом энтузиазме или вере невозможно. Это можно за полгода склепать поделку, и пребывать в состоянии эйфории, но уже ко второму году это быстро проходит, дальше наступает холодный расчет. Особенно, когда вы работаете на самом жестком рынке — разработки информационных систем, где чтобы заставить сменить чужую систему вы должны доказать, что вы на несколько порядков лучше. Но как показала жизнь есть простой способ это сделать. Просто быть на несколько порядков лучше — когда вы можете набирать разработчиков с открытого рынка: людей без IT-образования, тем самым вы можете набирать в том числе лучших (иначе вы проиграете в споре за них крупным модным компаниям), когда эти люди могут делать по 5 задач в день, когда их можно свободно переключать между задачами из разных областей и т.д., тогда у вас остаются только два конкурента лень и жадность (даже глупость отступает на второй план). Поэтому, что касается вопроса про деньги, поверьте мы уже достаточно зарабатываем просто за счет того, что скажем на рынке FMCG-ритейла Беларуси (а это второй по деньгам сегмент после банков) у нас практически не осталось конкурентов (все выбирают либо между нами, либо остаться с тем что есть).

Но вообще я так понял вы до сайта не добрались, там всего три страницы, с ответами на все ваши вопросы.

Это кстати, а не функциональный, а комбинаторный подход (функциональный это передача параметров в качестве функций, а этого тут нет, точнее есть, но в слегка извращенном виде в виде метакодов).

В любом случае я не совсем понял ваш тезис:
a) Такой язык уже есть. Можно тогда пример хоть одного близко похожего.
б) У него нет преимуществ. Специально для этого мы сделали сайт из 3-х страниц, где есть краткие преимущества, подробные преимущества и их сравнение. Если вы считаете что каких-то преимуществ нет, они не существенны, что же, можем здесь подискутировать. Хотя да я знаю, что на Хабре не принято отсылать на сторонние сайты, так что если нет, давайте просто дождемся следующих статей прежде чем делать выводы.
>> Она не подразумевает хранение значений, а свойство — подразумевает

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

>> вы до сайта не добрались

Да, не посмотрел сразу. Но исправился :) Там в части «Разрабатывайте просто» такой аргумент «против всех»:

>> Одна парадигма. Один язык

Или вот такое (в «Разрабатывайте быстро»):

>> Завершенная ERP-система среднего уровня сложности всего в 25K строках кода

Здесь на самом деле «всё не так просто (с)». Один язык и одна парадигма появились начиная с машинных кодов. Да, машинные коды позволяют написать и OLTP и OLAP, но вы же понимаете, что реальность внесёт здесь некоторые коррективы.

Ну а размер «средней ERP» — это вообще нечто абсолютно произвольное. Под такое определение подойдёт, например, 1С-Управление, требующее для написания ноль строк, ибо «всё украдено до нас (с)». И вы, получается, опять в проигрыше.

Я бы рекомендовал вам, хотя бы примерно, вспомнить — а зачем вы придумали ту или иную фичу в вашем языке? И от этого вам станет яснее, какие конкретно преимущества вы ожидали, изобретая данный кусок языка. Ну а поняв, вы сможете указать другим — вот так вот делается быстрее потому что…

Ну и в целом сам язык тоже не на пустом месте появился. Точнее — идея нового языка. Во введении вы его сравнили с SQL, и в целом очевидно, что раньше писали системы преимущественно на хранимых процедурах, так вот и покажите, что в сравнении с хранимками вы увидели вот такое-то преимущество, вот так-то облегчающее работу программиста. Хотя здесь стоит заметить, что хранимки — это обычно довольно убогий процедурный язык, не позволяющий гибко работать со сложными абстракциями, а потому даже небольшое повышение уровня абстракции языка даёт ту самую важную гибкость, ну и поэтому (весьма вероятно) вам понравилась идея нового языка. Только ведь в таком разрезе есть альтернатива — изучить другой, более мощный при работе с абстракциями язык. Вы сравнивали свой язык в этом отношении с более универсальными? И что вас не устроило? То есть, часто люди поддерживают нечто своё не потому, что оно лучше других вариантов, а просто потому, что оно понятнее этим людям, ведь они написали это нечто с нуля и знают много важных деталей, которые помогают им наращивать эффективность в отдельных местах. Только эти «отдельные места» быстро заканчиваются. То есть писать по шаблону формочки для ERP — это одно, а вот если потребуется усложнение алгоритма — здесь могут быть страшные засады.

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

Для примера — в функциональных языках привычной является функции типа fold, zip, которые агрегируют переданные в них данные, примерно как ваша конструкция GROUP, но отличие такое — эти функции можно написать самому, а не использовать библиотечные. То есть гибкость здесь в том, что не нужен новый язык для реализации важного алгоритма агрегирования данных. А у вас нужна новая конструкция, которую нельзя написать средствами языка. У вас гибкость, получается, заметно меньше.
Там в части «Разрабатывайте просто» такой аргумент «против всех»: "Одна парадигма. Один язык"

… что многие разработчики, кстати, сочтут недостатком.

В среде разработчиков вообще очень часто луддизм встречается. В этом случае простота в принципе недостатком считается.

Вопрос в том, простота ли это.

Ну а размер «средней ERP» — это вообще нечто абсолютно произвольное. Под такое определение подойдёт, например, 1С-Управление, требующее для написания ноль строк, ибо «всё украдено до нас (с)». И вы, получается, опять в проигрыше.

А вы вообще видели 1С-Управление торговлей и их код? Скачайте посмотрите. Там на порядок больше 25К строк кода, даже если не включать туда замаскированный в визуальное программирование код. Старое доброе процедурное програмирование с формированием SQL команд в строках.
Я бы рекомендовал вам, хотя бы примерно, вспомнить — а зачем вы придумали ту или иную фичу в вашем языке? И от этого вам станет яснее, какие конкретно преимущества вы ожидали, изобретая данный кусок языка. Ну а поняв, вы сможете указать другим — вот так вот делается быстрее потому что…

Вы не поняли, все фичи шли от потребностей. Фактически мы строили самолет в воздухе вместе с пассажирами. И у нас была очень эффективная метрика, если в конечном итоге заказчик звонит руководству, это значит очень важная проблема. То есть, если что-то тормозит, если разработчик долго работает над задачей, если особенности языка приводят к ошибкам, если разработчик не понимает чего то в языке, это все повод что-то пофиксить / доработать язык. И в конечном итоге мы его стабилизировали.
Только ведь в таком разрезе есть альтернатива — изучить другой, более мощный при работе с абстракциями язык. Вы сравнивали свой язык в этом отношении с более универсальными? И что вас не устроило?

Так нет ни одного даже близко похожего языка. Еще раз, SQL — используется в полной мере, lsFusion — надстройка над ним. Как вы вообще представляете, вот разработчик пишет:
FOR selected(Item i) DO
price(i) < — price(i) + 1;
Выполнять это императивно очень неэффективно. Но это можно скомпилировать в:
price(Item i) < — price(i) + 1 WHERE selected(i); и выполнить одним UPDATE запросом.
При этом разработчик не в курсе ни про SQL ни про сервер БД ни про сервер приложений. Чист как лист. Какой язык вы сюда прикрутите? И это мы еще до логики представлений не дошли.
В общем — я бы сказал, что хотелось бы увидеть некую теоретическую базу, показывающую, что вы действительно сдвинули с места ту или иную проблему программирования, а не, в общем-то, рекламные слова про «среднюю ERP».

Собственно и в статье есть про теоретический базис, и на сайте есть 32 преимущества (со ссылками на документацию и how-to), и есть сравнение этих преимуществ со всем, что есть на рынке по каждому из этих 32 преимуществ, чего там еще не хватает?
Для примера — в функциональных языках привычной является функции типа fold, zip, которые агрегируют переданные в них данные, примерно как ваша конструкция GROUP, но отличие такое — эти функции можно написать самому, а не использовать библиотечные. То есть гибкость здесь в том, что не нужен новый язык для реализации важного алгоритма агрегирования данных. А у вас нужна новая конструкция, которую нельзя написать средствами языка. У вас гибкость, получается, заметно меньше.

А например, там еще есть GROUP LAST InvoiceDetail i ORDER number(i) BY invoice(i);
Которые на самом деле если есть индекс по number будет выполняться на SQL-сервере как SELECT LIMIT 1, а еще туда надо возможно предикат с invoice протолкнуть, чтобы субд не посчитал подзапрос для всей базы, а потом join'л. Как тут эти fold'ы и zip'ы помогут?
Как тут эти fold'ы и zip'ы помогут?

Через разбор дерева выражений. Дальше все то же самое.

Через разбор дерева выражений. Дальше все то же самое.

И чем тогда это лучше языка? С языком хотя бы completion проще прикрутить, да и язык читабельнее.

Собственно мы поначалу пытались, но реально порог вхождения сильно повышался. Люди, которые до этого в IT не были, реально не въезжали.
И чем тогда это лучше языка?

Тем, что лучше обобщается. Только противопоставление неправильное, потому что это и есть язык. Чем один язык лучше другого?.. Ну, по-разному бывает.


С языком хотя бы completion проще прикрутить, да и язык читабельнее.

Мне кажется, вы что-то другое понимаете под деревом выражений.


sum seq = seq |> fold ((acc, x) -> acc + x)


Вот то, что в скобках после fold — это дерево выражений, которое можно преобразовывать во что угодно по вашему вкусу. Хотите — преобразуете в SQL.

sum seq = seq |> fold ((acc, x) -> acc + x)


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

Это всего лишь вопрос привычки к синтаксису. Вот вам то же самое на чистом ванильном C# (там, правда, будет проблема со сложением, но мы сделаем вид, что ее нет): seq.Aggregate((acc, x) => acc.Plus(x))


Ну серьезно, для системных программистов допустим, но для прикладников

А "прикладники" пишут seq |> sum (ну или seq.Sum()), и у них все хорошо. До тех пор, пока им не надо написать какую-то вещь, которую вы на уровне базовой библиотеки не стали, и тогда они достают fold и пишут сложнее.


(Вообще, конечно, это весьма оскорбительное противопоставление)

То есть по вашему синтаксически:
seq.Aggregate((acc, x) => acc.Plus(x))

Лучше чем:
GROUP SUM seq(x)
Серьезно?

Да, привычнее, для большинства программистов работавших с функциональным программирования. но большинство «прикладников» пишут не seq |> sum, а на ABAP, 1C или на Delphi+Oracle/MSSQL. Во всяком случае на постсовке. И на западе ландшафт еще веселее, там всякие Cache, Progress и куча еще кого обитает и им такой синтаксис тоже не близок.

В любом случае та же группировка это вершина айсберга, с событиями, ограничениями и агрегациями что делать? И это еще до логики представлений не дошли.
То есть по вашему синтаксически: seq.Aggregate((acc, x) => acc.Plus(x))
Лучше чем: GROUP SUM seq(x)
Серьезно?

Нет, я этого не говорил нигде. Сравнивать надо seq.Sum() против GROUP SUM seq(x), и разница окажется исключительно вкусовой.


Нет, первое хорошо тем, что я могу написать


seq
.Aggregate(((sum, cnt), x) => (sum.Plus(x),cnt.Plus(1)))
.Select((sum, cnt) => sum/cnt)

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


с событиями, ограничениями и агрегациями что делать?

Разбираться по месту. Я отвечал на вопрос, как в случае использования ФВП решать проблемы оптимизации.

Разбираться по месту. Я отвечал на вопрос, как в случае использования ФВП решать проблемы оптимизации.

К сожалению, по моему опыту лида, «разбираться по месту» — это значит «иди к лиду/архитектору, пусть скажет как делать». А хочется, чтобы была четкая схема, по которой человек (не лид) сам знал как делать, не отвлекая более дорогих людей.
А хочется, чтобы была четкая схема, по которой человек (не лид) сам знал как делать, не отвлекая более дорогих людей.

Это "разбираться по месту" делается на этапе разработки платформы, а не имплементации бизнеса. Поэтому тем, кто имплементирует бизнес (собственно, прикладным программистам) уже выдаются готовые рельсы, как конкретно реализуется каждая типовая задача.


Собственно, вопрос "ФВП против готовых агрегатов" — это тоже периода проектирования платформы, на этом промежутке еще нет людей, которые не "лиды/архитекторы".

Извините, но не очень понял — какой платформы? Можете все-таки примеры из жизни? То есть для разработки простенького бизнес-приложения, нужно сначала разработать платформу, а потом на ней само приложение?
Давайте может больше конкретики. Конкретные платформы, например.
Извините, но не очень понял — какой платформы?

Той самой, которая дает вам GROUP SUM.


То есть для разработки простенького бизнес-приложения, нужно сначала разработать платформу, а потом на ней само приложение?

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


Конкретные платформы, например.

Ваша, например. .NET, например.

Сравнивать нашу и .Net — это тоже самое, что сравнивать 1С и .Net. Как бы абсолютно разного уровня платформы для абсолютно разных разработчиков и целей. Вы согласны, что большинство 1С программистов вы не сможете переучить на .Net?
Назовите, пожалуйста, бесплатную высокоуровневую платформу (то есть где вам не надо заморачиваться общением клиента и сервера, сервера и базы данных) которую сможет освоить, грубо говоря, бизнес-аналитик?
Сравнивать нашу и .Net — это тоже самое, что сравнивать 1С и .Net.

А я их и не сравниваю. Вы просили привести пример платформы, чтобы было понятно, о чем я говорю, когда говорю о "разработке платформы" — вот вам пример. Не более того.


Назовите, пожалуйста, бесплатную высокоуровневую платформу (то есть где вам не надо заморачиваться общением клиента и сервера, сервера и базы данных) которую сможет освоить, грубо говоря, бизнес-аналитик?

А почему, собственно?

Потому что именно это и является одним из преимуществ платформы lsFusion. Ее может освоить человек, который не может освоить .Net, так как она значительно проще. Это является конкурентным преимуществом. Разве нет?
Ее может освоить человек, который не может освоить .Net, так как она значительно проще.

Это утверждение, скажем так, нуждается в доказательстве. Но не суть.


Это является конкурентным преимуществом. Разве нет?

Да, простота в освоении является конкурентным преимуществом. Я с этим нигде не спорил. Я даже не спорю, что у lsFusion есть определенное количество преимуществ по сравнению с .NET.

Допустим, в lsFusion мне не нужно


заморачиваться общением клиента, сервера и базы данных.

Значит ли это также и то, что я не могу этим заморочиться, так как эти процессы не находятся вне моего контроля?

У вас есть определенные рычаги управления. Например, можно задавать каким образом логика будет отображаться в базу данных. Тут точно также, как вы не можете напрямую влиять на планы выполнения запросов в базе данных, но в некоторых можете давать hint'ы.

И в целом Вы конечно можете всегда напрямую обратиться к базе данных через EXTERNAL или из Java кода через JDBC и делать что хотите под свою ответственность.
У вас есть рычаги, но более высокоуровневые. Скажем в базе вы управляете материализацией свойств (определяете, что хотите хранить, а что хотите — вычислять), и раскладыванием их по таблицам (можете вообще все свойства в одну таблицу положить, а можете наоборот каждое свойство в отдельную) и индексами. Плюс есть хинты всякие, но они остались от древних времен, когда оптимизаторы не были настолько умными, поэтому мы их пока даже в документации не описывали, но может в будущем опишем (логика такая же как в хинтах СУБД)

Что контролировать в общении клиента и сервера у меня пока фантазии не хватает. Ну общаются и общаются. Все сделано так что максимум один round-trip, особо улучшать некуда. Есть пару мелких настроек с асинхронностью впрочем, но ничего особенного.

Ну и всегда Java в вашем распоряжении, на ней все что угодно реально бесшовно подключается во все стороны и смотрится как родное.
Нет, я этого не говорил нигде. Сравнивать надо seq.Sum() против GROUP SUM seq(x), и разница окажется исключительно вкусовой.

Ок, а как h(y) = GROUP SUM seq(x) IF g(x) = y будет выглядеть?
Нет, первое хорошо тем, что я могу написать

Ок, тут это будет выглядеть как:
(GROUP SUM seq(x))/(GROUP COUNT seq(x))
И хоть это не самый оптимальный пример для lsFusion, все равно проще. И выполняться он будет одним запросом / подзапросом (платформа их сольет в один).
Разбираться по месту. Я отвечал на вопрос, как в случае использования ФВП решать проблемы оптимизации.

Я имел ввиду с точки зрения синтаксиса, этих абстракций в других языках в принципе не существует.
Ок, а как h(y) = GROUP SUM seq(x) IF g(x) = y будет выглядеть?

h y seq = seq |> filter (x => g(x) == y) |> sum


Ок, тут это будет выглядеть как:

Угу. А теперь fold ((agg, x) => agg*x). Всегда будет операция, которую вы не предусмотрели.


этих абстракций в других языках в принципе не существует

Ограничения точно есть (см. design by contract). Остальное, если его нет, реализовывать как абстракцию платформы (у вас, в общем-то, тоже, не понятно, это функциональность языка или платформы).

h y seq = seq |> filter (x => g(x) == y) |> sum

А теперь возьмите человека «с улицы» и попробуйте ему объяснить это по сравнению с:
h(y) = GROUP SUM seq(x) IF g(x) = y
Вы очень сильно удивитесь.
Угу. А теперь fold ((agg, x) => agg*x). Всегда будет операция, которую вы не предусмотрели.

А как вы ее в SQL выполнять собрались?
Ограничения точно есть (см. design by contract). Остальное, если его нет, реализовывать как абстракцию платформы (у вас, в общем-то, тоже, не понятно, это функциональность языка или платформы).

Ограничения именно в виде, что заданная функция должна всегда должна возвращать NULL? Поймите в высокоуровневых абстракциях реально с языком проще. Это нормально, человек привык к языку, он его использует в каждодневной жизни в конце концов.
А теперь возьмите человека «с улицы» и попробуйте ему объяснить это по сравнению с:

Меня не очень интересуют люди с улицы. Точнее даже совсем не интересуют.


А как вы ее в SQL выполнять собрались?

Во-первых, не собирался, в этом и прелесть. Во-вторых, курсором.


Ограничения именно в виде, что заданная функция должна всегда должна возвращать NULL?

Нет, ограничения в виде "данное условие всегда должно быть верно". Что, заметим, намного понятнее в терминах естественного языка.

Меня не очень интересуют люди с улицы. Точнее даже совсем не интересуют.

Вам повезло, а если бы вам надо было сводить бюджет расхода с расходами и рисками, очень бы интересовало.
Во-первых, не собирался, в этом и прелесть. Во-вторых, курсором.

Ну то есть все данные загоняем на сервер приложений и там вычисляем итерируясь по одному? У меня для вас плохие новости. Курсор тоже самое сделает на сервере БД, и думаете это сильно лучше?
Нет, ограничения в виде «данное условие всегда должно быть верно». Что, заметим, намного понятнее в терминах естественного языка.

Согласен. Но это когда у вас ровно одно значение, тогда можно ограничивать что условие всегда верно. Но когда у вас есть параметры у условия, то нельзя ограничивать, что для всех существующих параметров условие должно быть верно (так как количество всех возможных параметров бесконечно). Можно только ограничивать что ни для одного из существующих параметров данное условие не будет верно. Хотя к нашему спору про Language vs Library это имеет мало отношения.
Вам повезло, а если бы вам надо было сводить бюджет расхода с расходами и рисками, очень бы интересовало.

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


Ну то есть все данные загоняем на сервер приложений и там вычисляем итерируясь по одному?

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


У меня для вас плохие новости.

У вас нет для меня новостей хуже, чем "этот расчет нужно выполнить". Его все равно нужно выполнить, вопрос только в том, как я его запишу.


нельзя ограничивать, что для всех существующих параметров условие должно быть верно (так как количество всех возможных параметров бесконечно). Можно только ограничивать что ни для одного из существующих параметров данное условие не будет верно.

Мне казалось, "ни для одного из существующих параметров данное условие не будет верно" превращается в "для всех существующих параметров условие будет верно" операцией отрицания.


Возьмем, чтобы далеко не ходить, ваш же пример:


CONSTRAINT hostTeam(Game team) = guestTeam(team)

Достаточно написать Invariant(hostTeam(Game team) != guestTeam(team)), все равно вам надо проверять "при изменении у игры команды хозяев или команды гостей [...] условие равенства этих команд".


Или я что-то упускаю?

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

Ну значит ваши наниматели нашли «жирные» проекты, где заказчики готовы платить много и без особых претензий. Молодцы.
У вас нет для меня новостей хуже, чем «этот расчет нужно выполнить». Его все равно нужно выполнить, вопрос только в том, как я его запишу.

А если этот расчет будет выполняться тысячи раз, у вас забьется сеть, может начаться фрагментация памяти на сервере приложений, с процессорами начнут возникать вопросы и т.п. SQL по идее это может выполнить гораздо эффективнее.
Мне казалось, «ни для одного из существующих параметров данное условие не будет верно» превращается в «для всех существующих параметров условие будет верно» операцией отрицания.

Вообще говоря, не совсем. Дело в том, что NOT hostTeam(game)=guestTeam(game), это не тоже самое что hostTeam(game)!=guestTeam(game). Если у вас guestTeam(game) — NULL, то первое условие вернет TRUE так как hostTeam(game)=guestTeam(game) это NULL (все операторы сравнения возвращают NULL когда один из операндов NULL), а hostTeam(game)!=guestTeam(game) вернет NULL (по той же причине).
Фактически NOT hostTeam(game)=guestTeam(game) — TRUE для всех game которые не IS Game (например если в game передать Team). Тут конечно может возникнуть обманчивое впечатление, что раз задан класс параметра то NOT hostTeam(Game game) = guestTeam(game) должен проверять на то что game IS Game, но это не так. Фактически класс параметра это чисто фишка resolve'га (поиска свойства при парсинге) на сами вычисления он никак не влияет (собственно платформа кроме поиска этот класс никак не использует), то есть в lsFusion смешанная типизация — хочешь задавай класс хочешь нет (мы кстати первые лет 7 во всех проектах работали на неявной типизации, потом перешли на явную). Этот момент меня самого немного смущает, и возможно в будущих версиях мы все же сделаем что указание класса будет неявно добавлять IF game IS Game.
Ну значит ваши наниматели нашли «жирные» проекты, где заказчики готовы платить много и без особых претензий.

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


SQL по идее это может выполнить гораздо эффективнее.

Прекрасно. Напомню, что все началось с (вашего же!) вопроса "как это на SQL считать". Если может — будет посчитано на SQL.


все операторы сравнения возвращают NULL когда один из операндов NULL

Это у вас так. А в других языках совершенно не обязательно так.


Фактически NOT hostTeam(game)=guestTeam(game) — TRUE для всех game которые не IS Game

Опять же, это в вашем языке так. А в некоторых других языках это просто невозможное утверждение, потому что это условие никогда не может быть применено к объекту, который не приводим к Game.

Опять же, это в вашем языке так. А в некоторых других языках это просто невозможное утверждение, потому что это условие никогда не может быть применено к объекту, который не приводим к Game.

А вы вообще много языков знаете, где можно бегать по всем не NULL значениям функции? Это я к assertion'ам для функций с параметрами, а не просто для значений.
Только не надо приводить в пример приводить dbContext.table, потому что здесь уже я начну придираться, что это особенность платформы, а не языка.
А вы вообще много языков знаете, где можно бегать по всем не NULL значениям функции?

Я даже не знаю, что вы имеете в виду, что уж говорить о языках.


я начну придираться, что это особенность платформы, а не языка.

А смысл? Мы уже выяснили, что у вас это неразделимые вещи.

Я даже не знаю, что вы имеете в виду, что уж говорить о языках.

Ну допустим вы объявили f(a,b) в каком-то синтаксисе. Чтобы потом можно было сделать:
FOR f(a,b) DO
MESSAGE a + ',' + b + '->' + f(a,b);
А смысл? Мы уже выяснили, что у вас это неразделимые вещи.

Ну вы утверждали что в других языках есть похожие на ограничения абстракции. Я сказал что для этой абстракции нет аналогов в других языках, потому как для этой абстракции нужна операция итерации по всем не null значениям функции, а ее в других языках нет. И тут вы могли бы исхитриться и привести в пример dbContext.orders.Sum(). На что уже я бы возразил что это не часть языка.

Чтобы потом можно было сделать:
FOR f(a,b) DO
MESSAGE a + ',' + b + '->' + f(a,b);

Я, опять-таки, не понимаю, что это должно сделать (это, кстати, иллюстрация к понятности декларативного синтаксиса).


Я сказал что для этой абстракции нет аналогов в других языках, потому как для этой абстракции нужна операция итерации по всем не null значениям функции

Для абстракции — не нужна, в том-то и дело. Для ее конкретной реализации — возможно.

Я, опять-таки, не понимаю, что это должно сделать (это, кстати, иллюстрация к понятности декларативного синтаксиса).

Пробежать по всем не NULL значениям. Ну то есть на реальных примерах.
FOR selected(team) DO
     MESSAGE 'You selected ' + name(team);
FOR invoice(invoiceDetail) = invoice DO
     MESSAGE 'This invoice detail '+invoiceDetail+'  is in ' + invoice;

Странно конечно, при обучении вот с чем с чем, а с пониманием итерации по всем значениям функции проблем не было. Не композиция конечно, но и не рекурсия.
Для абстракции — не нужна, в том-то и дело. Для ее конкретной реализации — возможно.

А вы много знаете абстрактных языков, то есть без единой их реализации?
Пробежать по всем не NULL значениям.

Вот есть функция f(x, y) = x+y, где x, y — целые числа. Множество ее значений — все целые числа, NULL там нет. Что такое "пробежать по всем значениям"?


FOR selected(team) DO
     MESSAGE 'You selected ' + name(team);

Если selected — это функция, возвращающая множество, то вы описали тривиальный итератор, которых в языках навалом. И?..


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

Это еще одна иллюстрация к вопросу о том, можно ли объективно определить простоту обучения чему-то.


А вы много знаете абстрактных языков, то есть без единой их реализации?

Вы первым начали разговор об абстракциях.

Вот есть функция f(x, y) = x+y, где x, y — целые числа. Множество ее значений — все целые числа, NULL там нет. Что такое «пробежать по всем значениям»?

В этом случае, платформа выдаст сообщение что количество значений бесконечно. Как и в случае скажем при итерации по sum:
sum(d) = GROUP SUM sum(invoice) IF date(invoice) < d;
FOR sum(d) DO // будет ошибка
MESSAGE 'D: ' + d;

Но при этом скажем
// пробежит во всем sku для которых определена последняя дата поставки
FOR sum(lastSuppliedDate(sku)) DO
MESSAGE 'Sum of all invoices before last supplied date for sku : ' + name(sku) + ' is : ' + sum(lastSuppliedDate(sku));

Можно кстати написать хитрее:
FOR s=sum(lastSuppliedDate(sku)) DO
MESSAGE 'Sum of all invoices before last supplied date for sku : ' + name(sku) + ' is : ' + s;

То есть если операцию теоретически можно выполнить она выполнится.
Если selected — это функция, возвращающая множество, то вы описали тривиальный итератор, которых в языках навалом. И?..

Нет selected это не функция возвращающая множество это обычная функция возвращающая значение, то есть например:
selected = DATA BOOLEAN (Team); // вводится
// вычисляется
selected (Team t) = countPlayers(t) > 5;

Вы первым начали разговор об абстракциях.

Ок, замените слово абстракция в этих предложениях на понятие или термин, и перечитайте заново.
В этом случае, платформа выдаст сообщение что количество значений бесконечно [...] Но при этом [...] пробежит во всем sku для которых определена последняя дата поставки

Вот я про это и говорю: я не понимаю, что вообще вы имеете в виду. Вот есть запись FOR f(x) DO. Что в ней такое x? Просто идентификатор, на который потом можно ссылаться? Или что?


Нет selected это не функция возвращающая множество это обычная функция возвращающая значение

Тогда извините, но значений у этой функции ровно два: true и false. Так что вы явно имеете в виду итерацию не по значениям функции, а по чему-то другому.


Ок, замените слово абстракция в этих предложениях на понятие или термин, и перечитайте заново.

А ничего не изменится. Для понятия "ограничение" (или "инвариант", что то же самое, судя по вашим описаниям) не нужна "операция итерации".

Тогда извините, но значений у этой функции ровно два: true и false. Так что вы явно имеете в виду итерацию не по значениям функции, а по чему-то другому.

Имелась ввиду итерация по всем наборам аргументов этой функции, для которых функция возвращает не NULL.

Рассмотрим функцию f(x), где x — целое число. Как это сделать? Теперь возьмем x как строку. Что-то изменилось? Теперь возьмем x как пользовательский тип. Что-то изменилось?

Это работает для ограниченных конечных множеств, что не включает в себя множества целых чисел и строк. А вот для наших пользовательских типов это работает, потому что количество объектов этих типов в нашем случае конечно.

Эм.


Пример №1: type Login: string. Простейший пользовательский тип (фактически, просто синоним), имеющий все поведение строки. Что будет, если "итерироваться по всем наборам аргументов" функции len(x), где x имеет тип Login?


Пример №2: type Coord {int x, int y}. Тоже очень простой пользовательский тип. Что будет, если "итерироваться по всем наборам аргументов" функции dist(x, y), где x и y имеют тип Coord?

Второй случай в lsfusion будет выглядеть так:
CLASS Coord;
x(Coord c) = DATA INTEGER(Coord);
y(Coord c) = DATA INTEGER(Coord);

dist(Coord x, Coord y) = ...;

Итерация пойдет по всем парам существующих объектов класса Coord для которых dist не NULL. То есть в нашем случае (если мы в dist просто берем евклидову норму) для тех объектов, для которых x и y установлены не в NULL.

По первому примеру не совсем получится один в один, потому что у нас нельзя наследовать пользовательские классы от встроенных (в нашей терминологии строковые типы — встроенные). У нас это будет класс Login + свойство, принимающее на вход объект этого класса и возвращающее строку. Ну и итерация пойдет по всем объектам класса Login, у которых это свойство задано (в предположении, что len — это вычисляемое свойство, возвращающее длину строки, если строка не NULL).
Итерация пойдет по всем парам существующих объектов класса Coord

Что такое "существующие объекты"? Почему можно итерироваться по всем "существующим объектам" для координат, но нельзя итерироваться по всем "существующим объектам" для целых чисел (хотя вторых меньше чем первых)?

Что такое «существующие объекты»?

Созданные ранее объекты класса. В статье есть немного информации по операторам NEW/DELETE. Грубо говоря, объект в нашем случае — это запись в таблице БД (а, например, DATA-свойства — поля). Итерироваться мы будем по лежащим в базе объектам класса Coord (и их конечное число). На пустой базе при первом старте системы их будет 0, к примеру.
Итерироваться мы будем по лежащим в базе объектам класса Coord

То есть никакого магического "бегать по всем значениям функции", а есть простое "применить функцию ко всем объектам из некоего множества" (где множество по соглашению принимается равным множеству объектов в БД).


И тогда это все сводится к банальному map: db(Coord) |> map f (ну или Db<Coord>.Select(f), если вам трубы не нравятся). И это, да, достаточно тривиальный (по нынешним меркам) итератор.

Не ко всем объектам, а только к тем объектам, для которых свойство не равно NULL. И речь не только про одиночный объект, где все довольно тривиально, а про наборы (кортежи) объектов, если у свойства больше одного параметра. Да, и объекты при этом могут лежать в разных таблицах (иерархии классов). Тут Select будет уже не такой простой.
Не ко всем объектам, а только к тем объектам, для которых свойство не равно NULL.

Вы не поверите:


db(Coord) |> choose f

При этом если choose нет, его легко написать:


def choose f = map f >> filter Option.isSome

Тут Select будет уже не такой простой.

Вот ровно для этого и полезна композиция функций.


Но речь-то о том, что ничего принципиально невозможного, сложного или магического нет, не более чем синтаксический сахар.

Я понял, что сам увел обсуждение не в ту степь. Предлагаю пока забыть то, что я писал про записи в таблицах, это физическая модель, детали реализации. В lsfusion можно проитерироваться по всем объектам любого пользовательского класса. Можно ли, например, в C# проитерироваться по всем «живым» объектам, к примеру, класса System.IO.File?
Можно ли, например, в C# проитерироваться по всем «живым» объектам, к примеру, класса System.IO.File?

Нет, потому что там нет концепции "живого объекта" — в общем случае она бессмысленна: например, что конкретно понимать под "живым" объектом класса System.IO.File, и что будет служить identity этого объекта?


Однако, если речь идет об экземплярах конкретного подмножества типов (а у вас сделана именно такая оговорка), это несложно реализовать.

>> сам увел обсуждение не в ту степь

Ну почему же? Вы как раз наглядно показали корни вашей системы. Всё началось с активной работы с БД, далее вам захотелось «расширить и углубить (с)», ну и вы начали сочинять навороты вокруг стандартной реляционной модели, использующей под капотом довольно сложные алгоритмы для выполнения запросов и эффективного хранения данных на диске. В итоге получилась надстройка над SQL, которая в SQL же и конвертируется (как я понял). Отсюда все эти абстрактные заявления про «множество объектов» по которым что-то «пробегает». На самом же деле речь идёт о банальном выполнении селектов по таблицам, возможно in memory tables, но суть-то не меняется.

Вот начали бы вы описание языка именно с такой подачи — это простая настройка над БД, транслирующая наш псевдо-код в SQL выражения и работающая с данными из БД неявным образом. Далее же надо показать — зачем вы прячете от разработчика всё то, что получается в результате трансляции в селекты. Этим вы убиваете понимание происходящего, но что вы при этом добавляете? Мне это совершенно непонятно. Минус (огромный) вижу. Плюсы — сомнительны.
Ага, а SQL это простая настройка над машинным кодом транслирующая ваш псевдо-код в машинные инструкции. И зачем он прячет все эти машинные инструкции от разработчика, убивая понимание как это работает. Этим вы убиваете понимание происходящего ну и т.д.
Про работу SQL знают все, а про работу вашей платформы — ну человек 10 знают. Поэтому вы всё прячете, а SQL ничего не прячет. Просто сравните количество людей, сходу понимающих суть SQL и вашего языка.
Про работу SQL знают все

Издеваетесь? Вы вообще в курсе, что там под штук 40 разных типов узлов плана? Я уверен что даже вы их не знаете. Абсолютное большинство SQLем как большим черным ящиком пользуются.
Просто сравните количество людей, сходу понимающих суть SQL и вашего языка.

Я сравнивал, когда пытался людям из не IT в мониторе процессов объяснять, что что это за магическое заклинание, и что такое таблицы и JOIN'ы. Они смотрели на меня как баран на новые ворота, что за херню я им втираю.
>> Вы вообще в курсе, что там под штук 40 разных типов узлов плана?

Ну не надо так страшно пугать. Если встретились с незнакомым алгоритмом джойна — читаем доку и через пол-часика оптимизируем без проблем. Главное — общее понимание процесса.

>> Я сравнивал, когда пытался людям из не IT…

Ну вам всегда нужны уточнения типа «берём выборку из всё-таки хоть как-то причастных людей»?
Вот есть запись FOR f(x) DO. Что в ней такое x? Просто идентификатор, на который потом можно ссылаться? Или что?

Угадали. Параметр f, на который потом можно ссылаться.
Тогда извините, но значений у этой функции ровно два: true и false. Так что вы явно имеете в виду итерацию не по значениям функции, а по чему-то другому.

Да ровно два true и null. И в платформе можно проитерироваться по всем значениям, для которых эта функция true. А можно просто ее вызвать.
А ничего не изменится. Для понятия «ограничение» (или «инвариант», что то же самое, судя по вашим описаниям) не нужна «операция итерации».

Для реализации нужна. Для определения возможно и нет. Мы же это уже выяснили вроде.
И в платформе можно проитерироваться по всем значениям, для которых эта функция true.

Нельзя, если xint. Ну, если верить вашим словам.


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


Для реализации нужна.

Для вашей реализации. Для других — не обязательна.

Нельзя, если x — int. Ну, если верить вашим словам.

Можно, там человек не совсем правильно выразился. На самом деле нужно чтобы множество было конечно.
То есть например вот такая штука работает:
iterate(i,from,to) = RECURSION i=from STEP i=$i+1 AND i<=to;
FOR iterate(i, 1, 5) DO
MESSAGE i;

Хотя здесь i — int;
В принципе я думаю в ближайших версиях сделаем, чтобы и эта штука работала:
FOR i >= 1 AND i <= 5 DO
MESSAGE i;

Для вашей реализации. Для других — не обязательна.

Я честно не знаю как это реализовывать без такой операции. Даже теоретически не представляю. Как только увижу такую реализацию, сразу признаю что не прав. Готов съесть то, что скажете.
Но самое важное уже обсудили выше: это ничем не отличается от применения функции к множеству, просто у вас это множество имплицитно и предоставляется платформой.

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

"В этом случае, платформа выдаст сообщение что количество значений бесконечно". Помните, кто это сказал?


Я честно не знаю как это реализовывать без такой операции. Даже теоретически не представляю.

Ну вы на Code Contracts посмотрите, например. Или, хотя бы, на CONSTRAINT в обычной РСУБД.


жизнь на этом рынке заставила меня стать практиком и использовать более простые понятия

Дадада, "бегать по всем значениям функции" — это намного более простое понятие, чем "вычислить значение функции для всех элементов множества". А главное, можно делать вид, что это уникальная возможность.

«В этом случае, платформа выдаст сообщение что количество значений бесконечно». Помните, кто это сказал?

Да, но это не привязано к тому примитивный или объектный параметр. Точнее так с примитивным параметром количество значений может быть как конечным, так и бесконечным. С объектным кстати тоже NOT hostTeam(game) — TRUE на бесконечном множестве значений и FOR по нему выдаст ту же ошибку.
Ну вы на Code Contracts посмотрите, например. Или, хотя бы, на CONSTRAINT в обычной РСУБД.

Они только на первичные данные (поля) работают. CONSTRAINT на View нельзя повесить, как и Validation на любой метод.
Дадада, «бегать по всем значениям функции» — это намного более простое понятие, чем «вычислить значение функции для всех элементов множества». А главное, можно делать вид, что это уникальная возможность.

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

Ну да. И что?


Ок, вычисление множества всех не NULL значений любой функции — уникальная возможность?

Смотря как оно сделано. Если перебором значений параметров, то это весьма тривиально. Если анализом кода — то интересно, но я все равно не думаю, что уникально.


А у вас как?

Ну да. И что?

То что они работают в одном небольшом частном случае вас не смущает.
Смотря как оно сделано. Если перебором значений параметров, то это весьма тривиально. Если анализом кода — то интересно, но я все равно не думаю, что уникально.

Конечно не перебором, издеваетесь что ли? Можно считать, что да, анализом кода, хотя архитектурно там все конечно сложнее. И учитывая насколько это тяжело реализовать, я практически на сто процентов уверен, что уникально.
То что они работают в одном небольшом частном случае вас не смущает.

Нет, не смущает. Code Contracts работают в большем числе случаев.


Конечно не перебором, издеваетесь что ли?

Да нет, не издеваюсь.


Вот у вас есть функция f(x) = md5(x). Как именно вы определите множество ее значений?

Вот у вас есть функция f(x) = md5(x). Как именно вы определите множество ее значений?

Дискуссия идёт к вопросу о майнинге криптовалюты, но мы не про такие вычисления)

Ну то есть все-таки нет "вычисления множества всех не NULL значений любой функции".

Ну если запрограммируете это дело, то есть шанс завалить Золотого Тельца, мы не брались

Так все-таки, есть в lsFusion "вычисление множества всех не NULL значений любой функции", или нет?

Так все-таки, есть в lsFusion «вычисление множества всех не NULL значений любой функции», или нет?

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

Функция md5(x) — дискретная?

Функция md5(x) — дискретная?

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

Прекрасно. Из этого вытекает, что в lsFusion есть «вычисление множества всех не NULL значений» ее значений. Правильно?

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

Эм. В вашей замечательной платформе нет простой хэш-функции? Никакой?


Ладно, а substring у вас есть?

Нет, не смущает. Code Contracts работают в большем числе случаев.

Но все равно по сути с field'ами. А первичных данных обычно хорошо если 5% в сложных системах.
Вот у вас есть функция f(x) = md5(x). Как именно вы определите множество ее значений?

Текст функции md5? Ну вы же помните, что она на том же языке написана? В смысле что lsFusion не телепат и не AI и не умеет бегать по функциям написанным на другом языке (тут не тот случай как в дне независимости где хакер к незнакомой системе за ночь вирус смог написать).
Но все равно по сути с field'ами.

Не обязательно.


Текст функции md5?

Вот вам псевдокод.

Не обязательно.

Ok, я написал:
f(a) {
int x = 0;
for(int i=0;i<5;i++)
x+= g(a, i);
return x;
}

Я могу валидатор повесить на f, что он всегда должен быть больше 0?
Вот вам псевдокод.

Ну вы же помните, что она на том же языке написана?

Но такой на lsFusion вполне инкрементит, чисто с виду его на группировках, рекурсиях не так сложно реализовать.
Я могу валидатор повесить на f, что он всегда должен быть больше 0?

Да.


Но такой на lsFusion вполне инкрементит, чисто с виду его на группировках, рекурсиях не так сложно реализовать.

Прекрасно. Так как же получить множество значений этой функции?

Я все-таки еще раз влезу. Уже целая куча сообщений в этой ветке из-за непонимания друг друга. Дело в том, что когда NitroJunkie написал «множество всех значений функции» имел он ввиду все-таки (если я не прав, то скажи) все то же множество всех наборов аргументов, для которых функция определена (ее значение от этих аргументов не равно NULL). Область определения функции, если угодно.
множество всех наборов аргументов, для которых функция определена (ее значение от этих аргументов не равно NULL)

Эгм. Давайте с конца.


ее значение от этих аргументов не равно NULL

В этом смысле функция md5 (как и любая хэш-функция вообще) очень проста: ее значение никогда не NULL. А теперь вернемся к вопросу: как будет вычисляться это самое "множество всех наборов"?


А теперь на шаг раньше.


для которых функция определена

А почему, собственно, функция считается неопределенной, если она возвращает NULL? Или это опять такое умолчание, принятое в lsFusion просто потому, что оно там принято?

Да.

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

Мне тут правильно подсказали, что я видимо не совсем правильно сформулировал, имеется ввиду множество значений параметров функции для которых она не null. Хотя множество значений при этом естественно тоже можно получить. В данном случае она не null для всех натуральных чисел. Хотя пример конечно дурацкий.
она будет определять что для какого то значения параметра f изменилось?

Вот когда этот "параметр" меняется, тогда и будет проверяться.


(Ну, я так предполагаю, конечно, я сам не работаю с контрактами, не привязанными к аггрегату, ибо смысла нет)


Мне тут правильно подсказали, что я видимо не совсем правильно сформулировал

Это не избавляет нас от вопроса как же.

Вот когда этот «параметр» меняется, тогда и будет проверяться

Как это параметр может меняться? Меняться только field'ы могут, или я что-то про c# не знаю.
Вы с ней не работали, а я даже не представляю как она теоретически может работать, но вы точно уверены что возможность есть.
Как это параметр может меняться?

Легко.


Меняться только field'ы могут, или я что-то про c# не знаю.

Изменение поля — изменение объекта, такая вот суровая боль в языках с мутабельностью.


я даже не представляю как она теоретически может работать

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

Изменение поля — изменение объекта, такая вот суровая боль в языках с мутабельностью.

Это что-то новое. И как это работает? Вообще любое поле изменяется, и все-все validator'ы запускаются?
Ну, здесь мы на равных: я тоже даже теоретически не представляю себе, как может работать то, что вы утверждаете, что работает.

А оно работает. Вешаете CONSTRAINT на вычисляемую функцию и он работает. Могу рассказать как, но это не очень тривиально.
Вообще любое поле изменяется, и все-все validator'ы запускаются?

Если вам нужны полные контракты — да, именно так.


(ну то есть на самом деле, я не удивлюсь, если там уже прикрутили трекинг зависимостей, благо анализ дерева есть, но гарантия остается неизменной)


А оно работает.

Вы пока так и не рассказали, как же вычисляется множество всех аргументов, для которых md5 не равно NULL.

Если вам нужны полные контракты — да, именно так.
(ну то есть на самом деле, я не удивлюсь, если там уже прикрутили трекинг зависимостей, благо анализ дерева есть, но гарантия остается неизменной)

Может еще все и в SQL умеет транслировать? Тогда я не удивлюсь, если она еще и мысли читать научилась.
Вы пока так и не рассказали, как же вычисляется множество всех аргументов, для которых md5 не равно NULL.

Легко, тут по логике вычислений видно что вычисляется для натуральных чисел, значит множество равно множеству всех натуральных чисел. Но вы реально какой-то дурацкий пример взяли.
Может еще все и в SQL умеет транслировать?

Нет, не умеет. Оно существует на том уровне платформы, где SQL не считается данностью.


Я вам больше того скажу, я последние полтора года SQL в своих задачах обычно вижу в формате "давайте перельем данные из РСУБД туда, где нам удобно с ними работать", и на этом его роль заканчивается.


Легко, тут по логике вычислений видно что вычисляется для натуральных чисел, значит множество равно множеству всех натуральных чисел.

На таком уровне это неуникальная возможность.


Вопрос, однако, в том, как вы будете итерироваться по этому множеству (вроде как выше заявлялась такая возможность).

Нет, не умеет. Оно существует на том уровне платформы, где SQL не считается данностью.

Зашибись аргумент. То есть в жизни использоваться не может. То есть можно считать, что такой возможности нет. Так и запишем.
Я вам больше того скажу, я последние полтора года SQL в своих задачах обычно вижу в формате «давайте перельем данные из РСУБД туда, где нам удобно с ними работать», и на этом его роль заканчивается.

Ну это потому что вы с нормальными взрослыми бизнес-приложениями не сталкивались, столкнетесь будете все на PL/SQL переписывать (как это скажем во всем ритейле банках сейчас работает).
Вопрос, однако, в том, как вы будете итерироваться по этому множеству (вроде как выше заявлялась такая возможность).

Будем формировать SQL запросы. Например как в задаче про 2*. Такой ответ устроит?
То есть в жизни использоваться не может.

Может. Жизнь не ограничивается SQL.


Ну это потому что вы с нормальными взрослыми бизнес-приложениями не сталкивались

Вы не знаете, с чем я сталкивался, а с чем — нет.


Будем формировать SQL запросы.

Ну то есть, в итоге, перебором множества аргументов. О чем и шла речь.

Вы не знаете, с чем я сталкивался, а с чем — нет.

Ну это я сделал вывод по тому, что вы считаете что SQL это так, какая та маленькая часть IT.
Ну то есть, в итоге, перебором множества аргументов. О чем и шла речь.

Нет, как минимум, если там внутри композиции к примеру есть, будут индексы использоваться. А на самом деле там дохрена оптимизаторов, как у lsFusion сверху, так и у SQL внизу.
Ну это я сделал вывод по тому, что вы считаете что SQL это так, какая та маленькая часть IT.

Я этого не говорил.


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

Это если они применимы. Дальше начинаются оговорки.

Вешаете CONSTRAINT на вычисляемую функцию и он работает.

О, а вот давайте на жизненном примере. Есть пользователи, у пользователей есть пароли. Поскольку админ параноик, он запрещает пользователям иметь пароли, входящие в утекшие БД. Соответственно, периодически он выгружает эти самые утечки, и заливает их в ту же БД, где и живут пользователи с их паролями.


Как в вашей системе выражается ограничение "пользователь не может иметь пароль, входящий в блеклист"?

CONSTRAINT password(User u) == password(BlackListItem item) MESSAGE 'пользователь не может иметь пароль, входящий в блеклист'

Этот констрейнт проверяется как-то иначе, нежели "при добавлении или изменении пароля пользователя проверить, есть ли такой пароль в блеклисте" (ну то есть в хорошем случае — индекс, в плохом случае — перебор)?


(ну и понятно, что симметрично для добавления пароля в блеклист)

Хотя нет, я на самом деле, не прав, «симметрично» нельзя — добавление пароля в блеклист должно происходить вне зависимости от того, есть ли такие пароли у пользователей, так что проверка должна быть односторонней. Так можно сделать?


(понятно, что в полном бизнес-сценарии еще есть «если после добавления пароля в блеклист выяснилось, что есть пользователи с таким паролем, нужно инициировать для них процедуру сброса пароля», но это явно не ограничениями делается)

Да, можно.
CONSTRAINT CHANGED(password(User u)) AND password(u) = password(BlackListItem item) MESSAGE 'пользователь не может иметь пароль, входящий в блеклист'
Можно наверное прикольнее:
CONSTRAINT p=CHANGED(password(User u)) AND p = password(BlackListItem item) MESSAGE 'пользователь не может иметь пароль, входящий в блеклист'
Но это уже синтаксические развлечения.

Кул. Вопрос "как проверяется этот констрейнт" остается.

Там все не так просто, но если совсем грубо на пальцах во втором случае при изменении password'а (например для нескольких пользователей), будет делаться SELECT JOIN таблицы изменений пароля с таблицей черного списка. Это если самый простой случай все первично. Понятно, что password может быть вычисляемым от других свойств, лежащих в разных таблицах и т.п., тогда запрос будет сложнее, но магия как раз в том, что тому кто делает этот CONSTRAINT фиолетово.

Ну то есть так и есть: для каждого измененного пароля мы перебираем (умнее или тупее) черный список.


магия как раз в том, что тому кто делает этот CONSTRAINT фиолетово.

Проблема этой магии в том, что одно (разумное!) изменение бизнес-требований делает эту операцию из O(k log n) (где k — число паролей для проверки, n — число паролей в черном списке), или даже немного лучше, если вы умеете делать "хорошие" индексы по строкам, в O(kn). Но это да, фиолетово.

Ну то есть так и есть: для каждого измененного пароля мы перебираем (умнее или тупее) черный список.

Нет это делается одним запросом с JOIN. Никакого FOR'а нет.
Проблема этой магии в том, что одно (разумное!) изменение бизнес-требований делает эту операцию из O(k log n) (где k — число паролей для проверки, n — число паролей в черном списке), или даже немного лучше, если вы умеете делать «хорошие» индексы по строкам, в O(kn). Но это да, фиолетово.

А добавив материализацию и индекс (в одно слово), если это вдруг понадобится, оно опять вернется в O(k log n). Но это уже проблема не разработчика, а платформы, или в крайнем случае «db-администратора» (который может быть один на весь проект). Но не разработчика, который про все эти ваши O вообще не знает и знать не обязан.

И там кстати не kn, k+n или k logn + n.
Нет это делается одним запросом с JOIN. Никакого FOR'а нет.

Эмм. Вы так говорите, как будто JOIN — это не перебор.


А добавив материализацию и индекс (в одно слово), если это вдруг понадобится, оно опять вернется в O(k log n)

Неа. Вы даже не спросили, какое изменение, а уже говорите, что его можно реализовать.


Но не разработчика, который про все эти ваши O вообще не знает и знать не обязан.

Это и беда. Он не знает, и пишет код, а код кладет систему.


И там кстати не kn, k+n или k logn + n.

Вы, повторюсь, еще не знаете, что за изменение, но уже уверенно говорите, чего оно стоит.

Эмм. Вы так говорите, как будто JOIN — это не перебор.

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

Но, конечно, все что сделано через джойн, можно написать императивно — можно написать цикл и в цикле перебор массива o(n*k), а можно написать цикл и в цикле поиск по хеш таблице, например (o(n*logk)
Я бы сказал, что в 95% случаев, если это перебор, то там явно нужен индекс

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

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

Еще раз у нас разработчики практически без IT-бэкграунда, они ни про функциональное программирование, ни про SQL не слышали (ну может кто-то слышал, но ни разу близко не подходили).

И как думаете какой синтаксис им будет очевиднее / удобнее? (я сейчас про пример с GROUP SUM seq(x) сверху)
И как думаете какой синтаксис им будет очевиднее / удобнее?

Тот, которому научат.

Вопрос в сложности и возможности этого обучения.

А вот это приятный в своей открытости вопрос, потому что практически никакого способа доказать, что обучение языку X "проще и возможнее", чем языку Y, хотя бы потому, что нет формального способа это измерить.

Есть и очень простой. Эмпирический. Сколько из условных 100 человек можно обучить одному языку, а сколько другому. И нам такой эксперимент пришлось проводить, так как мы набирали людей условно «с улицы».

Этот эксперимент хоть сколько-нибудь валиден только в том случае, если у вас были одинаково способные преподаватели для обоих языков (и одинаковые все прочие условия, включая мотивацию).

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

Можно четко описывать контролируемые и неконтролируемые условия, и пытаться оценить их влияние. В данном случае я указываю на первый же очень важный фактор, влияние которого вы не упоминаете.

И что за фактор? Одинаково способные преподаватели? Okm можно расширить тест до 5 условных преподавателей, обучающих 100 условных человек. Такой тест да сложнее провести, но это же не повод это не сделать это, хотя бы умозрительно. Но да результаты будут более субъективными.
И что за фактор? Одинаково способные преподаватели?

Именно.


Такой тест да сложнее провести, но это же не повод это не сделать это, хотя бы умозрительно.

Гм. Умозрительно? И как же мы будет выяснять, результаты чьего умозрительного теста более валидны, вашего или моего?


Но да результаты будут более субъективными.

Это ровно то, о чем я сказал раньше.

>> Там на порядок больше 25К строк кода

Повторюсь — в абстрактной системе, где непонятна роль платформы и целый алгоритм можно выразить используя длинные строки, просто нет критериев для оценки.

Трансляция в SQL, конечно, местами сокращает код, но это работает лишь до момента, когда потребуются усложнения в алгоритмах. Поэтому вторая часть «25к строк» — предметная область и её сложность. Они опять не заданы. Хотя есть намёк на тип «учётная система», для которой (особенно ради выигрыша в неких абстрактных соревнованиях, а не для реального предприятия) можно наваять ТЗ, предполагающее лишь примитивные селекты да апдейты, что наверняка хорошо ложится в ваш язык. Но если, внезапно, заказчику нужна сложная логика?

>> Фактически мы строили самолет в воздухе вместе с пассажирами

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

>> Выполнять это императивно очень неэффективно

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

>> Собственно и в статье есть про теоретический базис

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

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

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

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

Нет, именно 25к, которая работает на реальных предприятий. Причем преприятиях с претензиями. Большими претензиями. И там как раз фокус в том, что формируются не простые апдейты, а такие запросы, которые вы руками не сможете написать. Если интересно, откройте исходники ERP и посмотрите насколько там простая логика.
Это не самый удачный подход. Надо хотя бы иногда сажать самолёт и тщательно рассматривать все его составляющие. Ну и улучшать, включая крупные изменения, типа замены крыла на вертолётный винт. Заказчик будет против? Ну ладно, только тогда не стоит говорить о качестве.

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

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

Декларативный стиль — это метрика того насколько язык высокоуровневый. То есть на насколько сложных абстракциях он строится.
>> а таких задач в реальной жизни меньше 2%

Доказать сможете? Если доказательством опять будет ссылка на реализованный проект на вашем языке, то подскажу — вы встроили в платформу те встретившиеся алгоритмы, которые как раз и выходят за пределы базового набора примитивных действий, обычно идентифицируемого аббревиатурой CRUD. То есть «подшаманили» ради нужных расширений, а теперь некорректно заявляете об охвате 98% алгоритмов. В следующий раз (у следующего заказчика) вам придётся снова подшаманить, потом ещё и ещё. И окажется, то 98% — было явной натяжкой.

>> это скорее комбинаторное, реактивное, логическое и событийное программирование

А теперь было бы неплохо расшифровать приведённые термины. Мною использованы стандартные термины, вы же придумали свои, поэтому расшифровка необходима.

Хотя да, такой подход «сверху», пусть даже через доморощенные термины, я поддерживаю.

>> Декларативный стиль — это метрика того насколько язык высокоуровневый

Процедура «всё прекрасно» может быть написана почти на любом языке. Обратите внимание на силу декларативной метрики в данном примере.
Доказать сможете? Если доказательством опять будет ссылка на реализованный проект на вашем языке, то подскажу — вы встроили в платформу те встретившиеся алгоритмы, которые как раз и выходят за пределы базового набора примитивных действий, обычно идентифицируемого аббревиатурой CRUD. То есть «подшаманили» ради нужных расширений, а теперь некорректно заявляете об охвате 98% алгоритмов. В следующий раз (у следующего заказчика) вам придётся снова подшаманить, потом ещё и ещё. И окажется, то 98% — было явной натяжкой.

У нас больше 40 заказчиков из разных областей, разных размеров с оборотами под миллиард долларов полностью автоматизированных на этой платформе генерящих по 10 задач в день (!). И я вспомню штук 5 задач (вроде прогнозирования продаж). Все остальное эту куча разных формул, группировок, разбиений и т.п.
А теперь было бы неплохо расшифровать приведённые термины. Мною использованы стандартные термины, вы же придумали свои, поэтому расшифровка необходима.

Ага даже википедию отредактировал:
Комбинаторное, реактивное , событийное, логическое.
Процедура «всё прекрасно» может быть написана почти на любом языке. Обратите внимание на силу декларативной метрики в данном примере.

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

По модульности что-нибудь скажете? Как много зависимостей между модулями? Сколько лет приходится тратить на поддержку изменений в бизнес-процессах заказчика? Сколько человек поддерживают те 25к строк кода, которые работают на каком-то предприятии?
По модульности что-нибудь скажете? Как много зависимостей между модулями? Сколько лет приходится тратить на поддержку изменений в бизнес-процессах заказчика? Сколько человек поддерживают те 25к строк кода, которые работают на каком-то предприятии?

Цитирую статью:
Вообще, эти три механизма (агрегации, наследование и полиморфизм), а также события и расширения (о расширениях позже в статье о физической модели) позволяют достичь если не идеальной, то очень близкой к ней модульности. К примеру, сейчас ERP состоит из приблизительно 1100 модулей. Соответственно, из них можно выбрать любое подмножество модулей и собрать из этого подмножества решение, в котором будет ровно то, что нужно заказчику. Так, у нас у некоторых заказчиков работает только непродовольственная розница (около 50 модулей), у некоторых только производство и опт, а у некоторых практически все 1100 плюс еще 300 своих.

Вообще можете открыть исходники платформы, любой модуль и там в заголовках REQUIRE. В IDE по ним даже граф можно строить.

Там же можно увидеть коммиты, но это только ERP общая кодовая база, есть еще модули конкретных заказчиков они во внутренних репозитариях. Сейчас несколько десятков заказчиков, с общим оборотом наверное под несколько млрд долларов, среди них есть как крупняки, так и достаточно мелкие, хотя у нас средний чек повыше 1С, то есть все же в среднем не меньше 20-30 одновременных пользователей. Поддерживает и дорабатывает около 10 человек (около 30-40 задач доработки в день где-то генерится)
>> сейчас ERP состоит из приблизительно 1100 модулей

Масштаб понятен. А теперь ещё интереснее — как вы во всей этой тысяче ещё не запутались?

>> Поддерживает и дорабатывает около 10 человек

Вообще получается 10 человеко-месяцев каждый месяц убивается на обслуживание изменений. За 10 человеко-месяцев упоминавшуюся систему на 25к строк можно написать (ну почти, то есть без тестирования и прочего отягощающего, плюс эффективно разработку организовать). В итоге получаем, что месяца за два-три-ну-пусть-четыре доработки становятся равны по сложности разработке с нуля. И теперь вопрос — а где выигрыш? Новый язык и многия обещания предполагают огромное сокращение затрат, ведь так? Но тем не менее по трудозатратам систему переписывают полностью раз в несколько месяцев, при чём не реализуют все процессы заказчика с нуля, а лишь слегка подправляют. И вот это «слегка подправляют» равно переписыванию с нуля по затратам. Так в чём выигрыш? Где гигантские сокращения времени разработки, количества ошибок, жалоб пользователей и т.д.?
Масштаб понятен. А теперь ещё интереснее — как вы во всей этой тысяче ещё не запутались?

IDE практически со всеми возможности на базе IDEA (забавно кстати что про нее никто не спросил) творит чудеса. Графы модулей, классов, структура класса, да и просто IDEA'кий крутой поиск.

То есть нашел нужный функционал, написал REQUIRE. Не хватает функционала, создал еще один класс / агрегацию, добавил реализацию, доделал EXTEND'ы. Вообще ООП, а точнее полиморфизм / наследование плюс событийное программирование очень сильно недооценивают в разработке бизнес-приложений, при помощи них можно очень круто декомпозировать сложность и не давать растить технический долг, даже при схем херак-херак и в продакшн.
Вообще получается 10 человеко-месяцев каждый месяц убивается на обслуживание изменений.

Тут другая математика. В основном эти люди дорабатывают решения крупных клиентов и очень часто переделывают то что есть, потому что клиенты постоянно экспериментируют, хотят что-то новое автоматизировать (некоторые настолько вошли во вкус что в ERP системе уже строительство начали автоматизировать) и т.п… По сути у каждого заказчика свое уникальное решение сильно отличающееся от остальных (потому что у каждого куча своих ноу-хау).

Тут конечно можно начать волынку, что это неправильно, что best-practice и все дела. Но как сказал нам один из первых крупных заказчиков, я вот построил этот крупный бизнес сам с нуля, а ты сколько их построил, чтобы рассказывать мне как это делать. И если бы я не правильно работал, я бы этого не смог сделать. И он прав, если он будет работать как кто-то другой крупнее его, он просто проиграет ему, потому что он меньше. А процессы кого то меньше его точно нет смысла брать. В общем все эти best-practice — это «все беды от мяса». Продвигают те кто просто не умеет адаптироваться под заказчика и постоянно меняться вместе с ним.
>> То есть нашел нужный функционал, написал REQUIRE

Вот как это выглядит в Eclipse — я нажимаю ctrl+shift+o и мне предлагается список одинаковых названий классов из разных пакетов. Я выбираю — и всё, ничего искать не надо, тем более что-то писать. А если имя класса уникально — даже выбирать не надо.

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

>> Вообще ООП, а точнее полиморфизм / наследование плюс событийное программирование очень сильно недооценивают в разработке бизнес-приложений

Это просто структурирование задачи. И естественно, этим многие и активно занимаются. Другое дело, что в мире гораздо больше даунов, которые… Ну в общем они могут много чего недооценить.

>> очень часто переделывают то что есть, потому что клиенты постоянно экспериментируют

Мне вспоминается обычное недовольство типа «вот здесь нет поля ХХХ» или «вот это система должна сама!». И выливается это всё в довольно простые действия по добавлению поля или выполнению простого расчёта с выводом результата. Большего от учётных систем редко требуют. Поэтому здесь скорее речь об организации процессов в разработке, в смысле производительность у вас, конечно, как у всех, и не зависит от инструмента (или слабо зависит), а доработки требуют 10 человек именно из-за неидеальности процессов. Хотя соглашусь — в больших конторах процессы ещё более страшные и там легко могут и 100 человек на ваши задачи посадить.
В итоге получаем, что месяца за два-три-ну-пусть-четыре доработки становятся равны по сложности разработке с нуля. И теперь вопрос — а где выигрыш?

Извините, вы некорректно сравниваете. Вы сравниваете написание с нуля с обслуживанием изменений, но изменения после написания с нуля все равно будут. Кроме того, число изменений зависит от заказчика (причем от нескольких, но я не об этом), а не от разработчиков, и независимо от того, на каком языке вы напишете, 10 человек работая с этим заказчиком за месяц потратят 10 человеко-месяцев на поддержку.

Так в чём выигрыш? Где гигантские сокращения времени разработки, количества ошибок, жалоб пользователей и т.д.?


А вообще есть хороший пример тут на блоге — Леруа Мерлин. У них IT-отдел 400 человек. И они обслуживают компанию с такими же оборотами как у наших клиентов. Но у нас их 40 разных, а у них один. И когда они тут описывают задачи, которые они героическими усилиями решает, это выглядит забавно, потому как у нас такие чуть ли каждый день решаются. И это 10 человек. Абсолютное большинство из которых, без сколько-нибудь значимого IT-бэкграунда.

Понятно что они еще и веб-сайт и еще что-то ведут, но при этом скажем у них и ERP-система и POS и скажем HR — сторонние. А мы у многих заказчиков и это закрываем.

Зато у них модные технологии.
Как уже отметили в комментариях — продажа не удалась, не видно чем этот неязык лучше, какие преимущества предоставляет. Разговоры мол наш бизнес успешен, а значит язык ого-го конечно чушь, успех бизнеса в последнюю очередь определяется технологиями — «кадры решают всё», тем более ничего не говорит успех на убогом постсовестком рынке где никто не хочет нормально работать.
На самом деле платформа для прикладного софта нужна, когда-то были Clipper/FoxPro которые удобно комбинировали возможности по созданию гуев с базой данных и какой-то логикой, сейчас нишу поглотили энтерпрайзные уродцы или узкоспециализованные решения.
Я бы вот хотел библиотеку для создания простых (без свистелок, просто функциональных) кроссплатформенных (включая веб) гуев.
Я бы вот хотел библиотеку для создания простых (без свистелок, просто функциональных) кроссплатформенных (включая веб) гуев.

А бэкенд, если не секрет, на чем писать собираетесь? Там логику всякую, например, ограничения по отгрузкам конкретному клиенту и т.д.
тем более ничего не говорит успех на убогом постсовестком рынке где никто не хочет нормально работать.

Не надо только хаять постсоветский рынок. Мне доводилось видеть, как и что работает у западных компаний. Так вот там все местами в разы хуже, чем у нас. Почитайте хотя бы блог Лероя. От многих поставщиков приходят инвойсы в виде текстовых файлов, куда просто выгружены их отчеты. На вопросы «а дайте, пожалуйста, REST API, WS или что угодно», они вас откровенно игнорируют.
Бэкэнд и на питоне можно написать, может не так удобно как на специализированном DSL, но вполне приемлимо.
Но это будет медленнее и дороже, чем на специализированном DSL. Разве нет? Хотите устроим паралимпиаду по программированию? :)
Всё зависит от того как считать, надо учесть, что этот DSL надо изучать, что будет делаться при разработке первой системы и скажется на скорости, примерно за то же время, на условном питоне, в процессе разработки первой системы, будет подобран набор библиотек/практик и получится нечто вроде DSL, соответственно при разработке последующих систем разработка будет быстрее.
Думаю, что DSL может быть значительно эффективнее, только при очень узкой специализации, т.е. не DSL для ERP, а, например, DSL для платёжной системы, регистратора доменов и т.п., но до такого видимо пока ещё не доросли.
Тем не менее, большинство ERP-систем сейчас пишется на базе платформ с DSL (например, Axapta/SAP/1C и т.д.). Может потому, что все-таки так эффективнее?
Давайте по существу. Возьмем простое приложение. По ссылке есть краткое описание и ссылка на демку. Это небольшая CRM-система, которую мы разрабатывали под себя (есть своя специфика). Я снял данные с timetracking'а: на нее ушло 250 часов. Причем ее делал человек, который никогда ни на чем кроме lsFusion, не разрабатывал. Сколько времени уйдет у Вас на написание аналогичного функционала с использование python и front-end библиотеки по вашему выбору?
Мы же про серверную часть, я о том и говорю, что все такие АРМы на 99% состоят из гуя и отчётов, серверная часть там просто микроскопическая и на питоне её также быстро можно написать, а вот гуй это проблема с которой и начинался этот тред.
Бэкэндеры будут с Вами несогласны. Как минимум на сервере вам нужно будет реализовывать всю валидацию, обновление агрегаций в базе данных и прочее. А это большой кусок работы. Плюс, предположим вам нужно сделать окно по списку из 10.000 значений. Вы же не потянете их на клиента сразу? То есть нужно будет хитрое взаимодействие. Так вот все это высокоуровневые платформы берут на себя. Поэтому их и используют.
Для больше части задач есть хорошие библиотеки/подходы/стандарты, ну например, если юзать REST, то инструменты поддерживающие OpenAPI, вроде connexion возьмут на себя всю рутину по валидации, сериализации, парсингу параметров и т.д., останется только написать код который выполняет действие.
То есть Вы предлагаете собирать миллион различных библиотек, потом как-то их дружить друг с другом для того, чтобы решить простую с точки зрения пользователя задачу.
Так можно долго дискутировать, но ответьте, пожалуйста, на вопрос: сколько времени у Вас займет реализовать вышеописанную задачу?
Изначально все началось с того, что уже все давно написано. Так вот назовите мне, пожалуйста, все технологии, которые для реализации такой задачи использовать и сколько у Вас ориентировачно времени это займет.
Вы всё время уводите разговор в сторону, а ведь смысл моего изначального комментария был достаточно ясен и он не в том, что DSL не нужны, а в том, что данный пост никак не убеждает в ценности данного DSL.
Пока продажа не состоялась, видимо потому что выбрана неверная стратегия, нужно не справку по языку приводить, а показать на живом примере, разобранном по шагам, как сей язык позволяет решать задачи лучше аналогов, чтобы его преимущества стали оцевидны всем кто решает такой класс задач.
Все это будет, но в следующих статьях. Но, к сожалению, многие вещи можно оценить только после самостоятельного, относительного длительного использования. Но постараемся показать на примерах.
Это так, но чтобы человек стал тратить время на изучения какой-то никому не ведомой технологии его нужно убедить, что технология реально ценна, а аргументы вроде «мы же лидеры на рынке», «да все используют DSL, чем мы хуже», «у нас чистых функций нет, но мы их упомянем чтобы благодать хаскела снизошла на нас» только порятят впечатление.
Согласен. Но, даже если не касаться основных преимуществ, есть одна существенная — LGPL лицензия. Назовите, пожалуйста, высокоуровневую ERP-платформу, на которой сможет писать человек уровня 1С-программист с бесплатной лицензией?
Предположим человек — умный сотрудник (но не программист) некоторой компании, которому нужно решить какую-то внутреннюю задачу. С технологией по такой лицензии, он может быстро разобраться, и наклепать себе простенькое приложение и использовать его внутри компании. В противном случае ему как минимум придется идти согласовывать бюджет с руководством, объяснять зачем ему это надо, искать исполнителей и т.д. Скорее всего он этим заниматься не будет и просто забьет. А тут есть возможность.
Это конечно плюс, но не отменяет вышесказанного, пока не показаны преимущества можно считать что условный, тоже свободный, питон с условной Odoo лучше.
Я сейчас не про ERP и CRM. А просто про какую-то небольшую задачку. Возьмите к примеру Турнирная таблица. Как думаете, ее сможет написать обычный пользователь на питоне? Быстро научите его пользоваться самим питоном + каким-то фронтенд фрэймворком? А потом еще это все связывать и деплоить.
На мой взгляд проще чем вашему DSL
Возможно со старта и сложнее. Но зато на этом DSL можно делать очень сложные вещи гораздо проще. В следующих статьях мы это покажем на примерах.
Это была вводная статья, чтобы потом на нее ссылаться, если человек захочет изучить глубже.
Давайте так, у вас видимо сложилось ложное впечатление что это продающая статья. Нет. У нас было два варианта или делать первым преимущества (но тогда нас запинали бы за маркетинг буллшит), или техническое описание (тогда мы получили бы за отсутствие ценности). Это хабр и мы решили второй вариант, но потерпите скоро продающие статьи появятся. Хотя если не терпится есть сайт.
Тем не менее, большинство ERP-систем сейчас пишется на базе платформ с DSL (например, Axapta/SAP/1C и т.д.). Может потому, что все-таки так эффективнее?

То что кто-то что-то делает, ничего не доказывает, кто их там поймёт, вон Salesforce вообще древнюю джаву поломал и использует, да ещё и на рынке успешен.
Кстати, если отбросить веб в требованиях кросслатформенности, то есть интересный фреймворк для гуёв, но ввиду что веб сечас обычно нужен, а я от гуёв далёк не дошли руки попробовать.
Все комментарии не читал, поэтому возможно повторюсь.
Первый вопрос — зачем вы стали изобретать этот язык? Что не устраивало в текущих, как общего назначения, так и специализированных(ABAP, 1C, FoxPro, VBA)?
Но человека пишущего сейчас на ABAP'е вы совсем не заинтересовали и это не смотря на то, что ABAP — ужасен и нелогичен.
Из интересного увидел какое-то хитрое разделение между серверами приложений и БД, но фокус в том, что чем больше там магии — тем хуже, ибо в если что-то начинает внезапно тормозить, хотелось бы понимать что именно и какие пути решения есть. SQL тут кстати выступает плохим примером — мне встречались случаи, когда запрос работавший годами несколько миллисекунд вдруг стал работать несколько минут из-за изменения плана его выполнения. А так как запрос был простой, то пришлось взять бубен и подставлять натуральные костыли, чтобы вернуть все как было. А теперь представим, что мне еще ко всему этому сложно понять, где вообще код исполняется…

P.S. Собираетесь ли вы делать типовые решения и как хотите(или уже) решать проблему обновления типового, но кастомизированного кода?
Первый вопрос — зачем вы стали изобретать этот язык? Что не устраивало в текущих, как общего назначения, так и специализированных(ABAP, 1C, FoxPro, VBA)?

Тут преимущества и их сравнение с ABAP, 1C, Foxpro и VBA.
Из интересного увидел какое-то хитрое разделение между серверами приложений и БД, но фокус в том, что чем больше там магии — тем хуже, ибо в если что-то начинает внезапно тормозить, хотелось бы понимать что именно и какие пути решения есть

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

«Как я вас понимаю»©. Современные SQL-сервера это вообще один большой набор эвристик. Поэтому над ним есть компилятор запросов, которые делают проталкивание предикатов, материализацию подзапросов (когда что-то идет не так) и т.п.
P.S. Собираетесь ли вы делать типовые решения и как хотите(или уже) решать проблему обновления типового, но кастомизированного кода?

Есть как минимум ERP, на основе которого внедряется много разных решений для бизнесов разных областей, размеров.
Первый вопрос — зачем вы стали изобретать этот язык? Что не устраивало в текущих, как общего назначения, так и специализированных(ABAP, 1C, FoxPro, VBA)?

Отличий очень много. Главное отличие, что lsFusion — это декларативный (как SQL, а не императивный) и функциональный язык. Те, что вы перечислили — классические императивные языки. Советую посмотреть, например, Турнирная таблица (там нету ни строчки императивного кода) и представить как его сделать на вышеперечисленных языках.

Что касается оптимизации SQL запросов и обновления типового, но кастомизированного кода, будут отдельные статьи. Кастомизация под заказчика делается через объявление новых модулей в репозиториях заказчика, которые расширяют функционал без изменений исходных модулей. Можете пока вкратце посмотреть Расширения.
Главное отличие, что lsFusion — это декларативный (как SQL, а не императивный) и функциональный язык.

createCity (FILE f)  { 

    LOCAL cy = STRING[20] ();
    LOCAL ne = STRING[100] ();

    IMPORT JSON FROM f AS FILE TO() cy = countryId, ne = name;

    IF NOT country(cy()) THEN {
        EXPORT JSON FROM code = '1', message = 'Некорректный код страны';
        RETURN;
    }

    NEW c = City {
        name(c) <- ne();
        country(c) <- country(cy());

        APPLY;
    }

    EXPORT JSON FROM code = '0', message = 'OK';
}

Каким образом с практической точки зрения это не императивное программирование?

Спасибо, кэп.


Я просто не понимаю, в чем смысл заявления "это декларативный и функциональный язык", если на нем можно прекрасно написать императивный код (и, похоже, в каких-то задачах иначе просто нельзя).

Потому что другие языки могут сделать такое только императивным кодом, а в lsFusion это сделано комбинаторным программированием. Это не заявление — это факт.
Потому что другие языки могут сделать такое только императивным кодом,

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


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

На моей практике (а я обучал людей без какого-либо опыта программирования) декларативному обучить гораздо проще чем императивному. Проблема в императивщине в том, что там есть состояние, и человеку нужно иметь в голове «дебаггер», чего у большинства людей без опыта программирования нету.

Ну, у вас такая практика. С моей она, скажем, не совпадает, но это, к сожалению, ничего не значит.

Я вот, например, не обращаясь постоянно к пояснениям в тексте, не могу прочитать пример с турнирной таблицей и понять, что там происходит.

Кстати реально интересно, а какие строки именно непонятны? Все же язык text-based, а не symbol-based, то есть более громоздкий, но и более человеческий. Да работа с NULL'ами не очевидна, в частности этот OVERRIDE с 0 (там на самом деле можно упростить, но я например подумал что ретушировать какие-то вещи специально не совсем правильно). Но в остальном? Понятно, что у меня глаз замылен и мне все кажется простым, поэтому очень интересно узнать мнение со стороны человека, которому непонятно и который умеет формулировать свои мысли.
Кстати реально интересно, а какие строки именно непонятны?

name 'Название команды' (team) = DATA STRING[30] (Team) IN base;

Что такое IN base?


date 'Дата' = DATA DATE (Game);
hostTeam = DATA Team (Game);
guestTeam = DATA Team (Game);

Почему какие-то объекты имеют строковый (?) примитив после них, а какие-то — нет?


name 'Название команды' (team) = DATA STRING[30] (Team) IN base;
date 'Дата' = DATA DATE (Game);
hostTeamName 'Хозяева' (Game game) = name(hostTeam(game));

Почему name объявляется (team), но date объявляется без (game)? Почему hostTeamName объявляется с (Game game), а name — просто с (team)?


CONSTRAINT hostTeam(Game team) = guestTeam(team) CHECKED BY hostTeam[Game], guestTeam[Game] MESSAGE 'Хозяйская и гостевая команды должны быть разными';

Про то, что ограничения привычнее читать наоборот, я уже писал. А вот почему разные скобки в CONSTRAINT hostTeam(Game team) и CHECKED BY hostTeam[Game] — и вовсе непонятно.


    winOT 'ПО',
    winSO 'ПБ'

Без комментариев.


resultName 'Имя' (GameResult game) = staticCaption(game) IF game IS GameResult IN base;

Что такое staticCaption? Что здесь значит IN base (и к чему он применяется)? Каково значение resultName(game), если условие не выполнено?


result (Game game) = OVERRIDE userResult(game), (GameResult.win IF ((hostGoals(game) (-) guestGoals(game)) > 1 OR (guestGoals(game) (-) hostGoals(game)) > 1));

OVERRIDE обозначает, что мы меняем что-то ранее определенное, наверное userResult(game), но почему?


((hostGoals(game) (-) guestGoals(game)) > 1 OR (guestGoals(game) (-) hostGoals(game)) > 1)

Появились непонятные операторы в скобках, но, наверное, "здесь так принято". Что занятнее, так это то, что похоже, здесь записано правило "если разница голов больше одного", но она зачем-то записана двумя вычитаниями и OR вместо существенно более понятного |hostGoals - guestGoals| > 1.


hostGamesPlayed = GROUP SUM 1 BY hostTeam(Game game);

Гм. SUM 1 — это, наверное, COUNT. При этом там раньше написано GROUP, так что наверное, что-то по чему-то группируется, но что?


OVERRIDE [GROUP SUM 1 BY winner(Game game), result(game)](team, type)

Сочетание почти всего, что выше: OVERRIDE, двух вариантов скобок, SUM 1 и GROUP непонятно по чему.


Дальше более-менее то же самое, я, пожалуй, продолжать не буду.

Спасибо за подробный ответ.
Что такое IN base?

В базовой группе свойств, хотя согласен группы свойств не настолько очевидное понятие, хоть и достаточно простое.
Почему какие-то объекты имеют строковый (?) примитив после них, а какие-то — нет?

А из их содержания не очевидно, что это их заголовок? То есть серьезно не догадались?
Почему name объявляется (team), но date объявляется без (game)? Почему hostTeamName объявляется с (Game game), а name — просто с (team)?

Хороший вопрос, к тому кто делал пример (team) в первом случае не обязательно и непонятно почему хотя бы одинаково не сделал. По хорошему надо убрать тогда возможно обоих вопросов не будет. Вообще это язык с необязательной типизацией, если можно по имени найти свойство, класс можно не указывать, если есть несколько с одинаковым именем придется указывать (иначе ambigious будет)
Про то, что ограничения привычнее читать наоборот, я уже писал. А вот почему разные скобки в CONSTRAINT hostTeam(Game team) и CHECKED BY hostTeam[Game] — и вовсе непонятно.

Про ограничения согласен, но почему так, мы сверху уже обсудили. В квадратных скобках это явное указание класса для поиска свойства (так как тут нет контекста а в примере возможно есть еще свойство с именем hostTeam, если нет, то можно не указывать). Хотя зачем вообще в пример CHECKED BY включили, это достаточно специфичная магия (чтобы когда диалоги выбора выдавались там исключалась домашняя / гостевая команда). Это конечно круто, но не для базового примера.
Без комментариев.

Это классические enum'ы с заголовками. Вас заголовки смутили?
Что такое staticCaption?

Заголовок в enum'ах сверху. Согласен, не очевидно.
Что здесь значит IN base (и к чему он применяется)?

Ну по аналогии с первым примером к свойству. Ну я бы возможно вообще эти группы свойств из примеров исключил, надо подумать.
Каково значение resultName(game), если условие не выполнено?

NULL, но понимание NULL это уже минимальная essential complexity, без нее собственно и логика DATA свойств не сойдется в голове.
OVERRIDE обозначает, что мы меняем что-то ранее определенное, наверное userResult(game), но почему?

Ну тут надо представлять логику как в хоккее начисляются очки и результаты. Тут да исходили из предположения что все ее знают. Но очевидно что не все следят за хоккеем :)
Появились непонятные операторы в скобках, но, наверное, «здесь так принято». Что занятнее, так это то, что похоже, здесь записано правило «если разница голов больше одного», но она зачем-то записана двумя вычитаниями и OR вместо существенно более понятного |hostGoals — guestGoals| > 1.

Особенность работы с NULL'ами (5+NULL=NULL, а 5(+)NULL=5), но если забить на них то обычные +.Хотя тут чудес не будет либо не NULL суммы будут не очевидны либо NULL. Но наверное все же можно было пример переделать без этих скобочных штук. Почему abs не использовали сам не понимаю.
Гм. SUM 1 — это, наверное, COUNT. При этом там раньше написано GROUP, так что наверное, что-то по чему-то группируется, но что?

Игры по командам. В IDE кстати параметры по которым идет итерация подсвечиваются специальным цветом. Но тут да SQL-стиль, не так очевидно, возможно hostGamesPlayed(team) = GROUP SUM 1 IF hostTeam(game) = team было бы проще, но это возможно только вам так как вы к ФП видимо больше привыкли.
Дальше более-менее то же самое, я, пожалуй, продолжать не буду.

Ну про формы (логику представлений) было бы интересно, так как я как раз про них статью пишу, чтобы понять на что обратить внимание.
В базовой группе свойств

Понятнее не стало.


А из их содержания не очевидно, что это их заголовок?

Нет.


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

А не важно, почему так, важно, что это плохо читается "человеком со стороны", на что вы выше так упирали.


Это классические enum'ы с заголовками. Вас заголовки смутили?

Нет, меня смутило то, что непонятно, что это все означает. Я понимаю, что это enum, я не понимаю его бизнес-смысла.


NULL, но понимание NULL это уже минимальная essential complexity

Не минимальная. Монада either (или монада maybe) прекрасно позволяют обойтись без этой сложности. То, что вам так привычно, потому что в SQL везде было так — это, конечно, прекрасно, но это просто ваш опыт.


Ну тут надо представлять логику как в хоккее начисляются очки и результаты.

Да я даже из кода не могу понять, что происходит.


Особенность работы с NULL'ами (5+NULL=NULL, а 5(+)NULL=5)

… которая опять ничем не объясняется, кроме того, что вы так решили.


Почему abs не использовали сам не понимаю.

А вы говорите "понятное декларативное программирование".


Игры по командам

А как понять, что игры?


В IDE кстати параметры по которым идет итерация подсвечиваются специальным цветом

"декларативное программирование понятнее". да.


возможно hostGamesPlayed(team) = GROUP SUM 1 IF hostTeam(game) = team было бы проще

Проще было бы COUNT game WHERE hostTeam = @team (если мы в терминах SQL-like говорим), или games.Count(g => g.hostTeam == team), если мы говорим в терминах ФВП. Обратите внимание, что первая запись просто читается как естественный язык (не очень грамотный, но не суть).

Нет.

То есть вы читаете
name 'Название команды' (team) = DATA STRING[30] (Team) IN base;
date 'Дата' = DATA DATE (Game);
hostTeamName 'Хозяева' (Game game) = name(hostTeam(game));

и думаете, чтобы это могло быть. Даже интересно, а какие варианты у вас были?
Нет, меня смутило то, что непонятно, что это все означает. Я понимаю, что это enum, я не понимаю его бизнес-смысла.

А бизнес-смысл enum'ов в .net вы представляете. Тут собственно все тоже самое.
Не минимальная. Монада either (или монада maybe) прекрасно позволяют обойтись без этой сложности. То, что вам так привычно, потому что в SQL везде было так — это, конечно, прекрасно, но это просто ваш опыт.

Даже я не пойму как, а поверьте у меня очень большой бэкграунд в IT. Но если вы считаете, что это не только просто но и проще чем в примере, ок ваше право. Я услышал то что хотел.
… которая опять ничем не объясняется, кроме того, что вы так решили.

Да аналогов в других языках не было, пришлось решать.
А вы говорите «понятное декларативное программирование».

А причем тут это. Человек в любом языке может вместо a+b-c, написать a+d+b-c-d.
А как понять, что игры?

Ну потому, что параметров кроме игр там нет. И вообще кроме команды и игры в этой строке ничего нет. Тут собственно два варианта :)
«декларативное программирование понятнее». да.

Все относительно. Приведите пример где понятнее. А потом возьмите двух человек не из IT и попробуйте объяснить им на одном и втором языке. А мы перепробовали много синтаксисов пока подобрали самый простой.
Проще было бы COUNT game WHERE hostTeam = team (если мы в терминах SQL-like говорим), или games.Count(g => g.hostTeam == team), если мы говорим в терминах ФВП. Обратите внимание, что первая запись просто читается как естественный язык (не очень грамотный, но не суть).

Тут я согласен что для count синтаксический сахар уже давно напрашивается:
GROUP COUNT hostTeam(game)=team, на самом деле мы такой функционал в язык добавляем за час обычно, может завтра и добавлю кстати. Изначально кстати была идея еще GROUP убрать, то есть COUNT hostTeam(game)=team. Но это уже совсем перебор был бы.
Даже интересно, а какие варианты у вас были?

Комментарий, например.


А бизнес-смысл enum'ов в .net вы представляете.

Правильно именованных? Да, конечно.


Даже я не пойму как, а поверьте у меня очень большой бэкграунд в IT.

"Большой" — не означает "всеобъемлющий". Приведенные монады — это стандартное для ФП представление того, что в SQL представляется NULL.


Да аналогов в других языках не было, пришлось решать.

Ну то есть вы не слышали про non-nullable types, вы не слышали про ???


Ну потому, что параметров кроме игр там нет.

Вот только что у вас "параметр" — тоже не всегда понятно.


Приведите пример где понятнее.

Ну так и привел буквально строчкой ниже.

Комментарий, например.

Я конечно понимаю, что вы ругаете нас за свой синтаксис. Но мы его делали как вынужденную необходимость, а не ради того чтобы отличаться. И делать комментарий строковым литералом… Мы же не делаем язык ради языка. Как раз там где можно было использовать общепринятый синтаксис мы его старались использовать. Ну правда стараясь оставлять язык в едином стиле — word-based.
Правильно именованных? Да, конечно.

То есть в примере их слишком коротко назвали. Ок, возможно, но это как вы сами понимаете не проблема языка.
«Большой» — не означает «всеобъемлющий». Приведенные монады — это стандартное для ФП представление того, что в SQL представляется NULL.

Я под понимаем NULL, имел ввиду что при создании первичного свойства, человек должен понимать, чему равны по умолчанию все его значения. То есть первым должен быть не вопрос, что вернет f(a) IF g(a), когда g(a) — NULL, а я создал свойство f = DATA INTEGER (A); что оно вернет если я к нему обращусь.
Ну то есть вы не слышали про non-nullable types, вы не слышали про ???

И как ?? нужно по вашему было использовать для оператора сложения не чувствительного к NULL?
Вот только что у вас «параметр» — тоже не всегда понятно

А что это по вашему может быть? Мне кажется любому школьнику на доске напиши f(a) и спроси что такое a, он скажет параметр. Хотя правильно возможно будет аргумент :)
Ну так и привел буквально строчкой ниже.

А как в нем парсер должен догадываться какие параметры у hostTeam и в каком порядке они туда передаются. И что это за собака перед team?
Вы вообще понимаете, что текущий синтаксис lsFusion это синтаксис используемый в математике, которую в частности изучают в школе. А ваш синтаксис даже в университете не всегда изучают.
Ок, возможно, но это как вы сами понимаете не проблема языка.

Это не проблема языка, это проблема примера. Но пример показывает то, как люди пишут на языке — те самые, которых вы обучаете за какие-то там короткие сроки.


при создании первичного свойства, человек должен понимать, чему равны по умолчанию все его значения

Да, должен. Нет, ответ не обязательно NULL.


И как ?? нужно по вашему было использовать для оператора сложения не чувствительного к NULL?

А не надо делать нечувствительный к NULL оператор сложения, нужно избавляться от NULL под оператором сложения. А для этого ?? прекрасно помогает: (some ?? 0) * (other ?? 1).


А что это по вашему может быть?

Например, тип. Как в f(int).


А как в нем парсер должен догадываться какие параметры у hostTeam и в каком порядке они туда передаются.

У hostTeam в моем примере нет параметров, это обычное свойство: g.hostTeam.


И что это за собака перед team?

Самый обычный SQL-параметр.


Вы вообще понимаете, что текущий синтаксис lsFusion это синтаксис используемый в математике, которую в частности изучают в школе.

Нет, не понимаю. Я такого синтаксиса в школе не изучал.

Это не проблема языка, это проблема примера. Но пример показывает то, как люди пишут на языке — те самые, которых вы обучаете за какие-то там короткие сроки.

Они да говнокодят. И говнокодят по страшному. Но так как этот говнокод благодаря многим механизмам очень хорошо декомпозируется, технический долг практически не растет. Я честно говоря сам был удивлен, когда увидел это в живую.
Да, должен. Нет, ответ не обязательно NULL.

А в lsFusion именно NULL. Но почему-то с DATA у вас такого вопроса не возникло.
А не надо делать нечувствительный к NULL оператор сложения, нужно избавляться от NULL под оператором сложения. А для этого ?? прекрасно помогает: (some ?? 0) * (other ?? 1).

Там есть другая фишка что 5 (+) -5 должен быть NULL. Это очень важно с точки зрения инкрементальности: грубо говоря если вы знаете значение что значение a + b = c, и знаете что a изменяется на na, как обновить c не читая b? к нему нужно добавить na — a. Но тут будет вопрос если мы получим 0 в результате, значит ли это что c равно 0 или оно равно NULL, для этого придется прочитать b. С NULL не чувствительным оператором такой проблемы нет 0 это NULL и b читать не надо. Плюс с парадигмой когда 0 равно NULL во многих случаях проще работать, например когда
currentBalance (sku, stock) = income(sku, stock) (-) outcome(sku, stock), имея 0 равным NULL, можно спокойно делать FOR currentBalance(sku,stock) DO и бегать именно по всем товарам которые есть на остатках. Поэтому работу с NULL важно scope'ть к оператору, а не операндам. Но при этом случаев когда 0 при сложении нужно отличать от NULL тоже очень много например в задачах с надбавками и т.п.
У hostTeam в моем примере нет параметров, это обычное свойство: g.hostTeam.

Вы имеете ввиду есть, но один. Ок, теперь у вас у hostTeam два параметра — ваши действия.
Самый обычный SQL-параметр.

А зачем там собака? Почему просто как в lsFusion и в вашем любимом c# не использовать имя параметра.
Нет, не понимаю. Я такого синтаксиса в школе не изучал.

А как вы в школе функции записывали на доске? Неужели f a b?
Они да говнокодят. И говнокодят по страшному.

И вам, видимо, положить. Мне — нет.


А в lsFusion именно NULL

Это придуманное вами правило.


Но почему-то с DATA у вас такого вопроса не возникло.

Потому что так часто делают.


Там есть другая фишка что 5 (+) -5 должен быть NULL.

Гм. Нет, такому меня в школе не учили. И потом никогда не учили. И нет, я не хочу работать с такой системой.


Вы имеете ввиду есть, но один.

Нет, я имею в виду "нет параметров".


Ок, теперь у вас у hostTeam два параметра — ваши действия.

Гм, а что, это какой-то вопрос? def hostTeam(a, b) = .... Если типы a и b выводимы, компилятор их выведет, если нет — надо будет написать def hostTeam(int a, string b).


А зачем там собака?

Спросите у тех, кто делал SQL-параметры в T-SQL, я не знаю.


А как вы в школе функции записывали на доске? Неужели f a b?

В школе-то мы писали f(a), но это означало именно функцию от одного параметра, а не "возьмите некое множество, выберите из него элемент, который обозначьте a, примените к нему функцию, повторите".

И вам, видимо, положить. Мне — нет.

На рынке ИС в прикладном программирование вы без говнокода не обойдетесь. Весь вопрос в том насколько технология, которую вы используете позволяет вам декомпозировать сложность и не растить технический долг при этом.
Гм. Нет, такому меня в школе не учили. И потом никогда не учили. И нет, я не хочу работать с такой системой.

А вас никто и не заставляет. Но когда те кто хотят работать будут решать бизнес-задачи в раз 5 быстрее вас, возможно жизнь заставит. А точнее ваш работодатель. Про SQL тоже так сначала говорили (а этот язык куда мозгодробильнее), а потом всем пришлось изучать.
Нет, я имею в виду «нет параметров».

Ну как же нет. Домашняя команда определяется для чего? Для матча, значит один параметр. Остаток определяется для чего? Для склада и товара, то есть два параметра.
Гм, а что, это какой-то вопрос? def hostTeam(a, b) =… Если типы a и b выводимы, компилятор их выведет, если нет — надо будет написать def hostTeam(int a, string b).

Не вы мне ту вашу конструкцию полностью запишите, ну и заодно как будет выглядеть, h© = COUNT f(a,b) + g(a) IF h(a) = c
Спросите у тех, кто делал SQL-параметры в T-SQL, я не знаю.

Так вы же более эффективный синтаксис предлагали, а теперь не знаете зачем.
В школе-то мы писали f(a), но это означало именно функцию от одного параметра, а не «возьмите некое множество, выберите из него элемент, который обозначьте a, примените к нему функцию, повторите».

Там речь шла о другом, вы когда увидели бы в школе f(a) и вас спросили бы что такое a. Вы бы ответили параметр. А сейчас почему-то забыли.
На рынке ИС в прикладном программирование вы без говнокода не обойдетесь.

Вопрос только в том, стремитесь вы его преумножать или уменьшать.


Но когда те кто хотят работать будут решать бизнес-задачи в раз 5 быстрее вас, возможно жизнь заставит.

Я эту песню слышу лет десять, и пока что-то ничего не поменялось.


А точнее ваш работодатель.

Это очень вряд ли.


Про SQL тоже так сначала говорили (а этот язык куда мозгодробильнее), а потом всем пришлось изучать.

Вот прямо всем? Я могу не особо напрягаясь найти вокруг себя много людей, занятых в бизнесе и разработке бизнес-приложений, которые SQL не знают (или знают на уровне "только что прочитал документацию").


Домашняя команда определяется для чего? Для матча, значит один параметр.

Нет, не так. Домашняя команда — атрибут матча. Непараметризованный.


ту вашу конструкцию полностью запишите

Какую конкретно? Вы уж озвучьте задачу заново и полностью, потому что в исходной задаче для параметра места не было.


h© = COUNT f(a,b) + g(a) IF h(a) = c

А что такое COUNT f(a,b) + g(a)? Там даже порядок выполнения операторов непонятен.


Так вы же более эффективный синтаксис предлагали, а теперь не знаете зачем.

От того, что я не знаю, зачем так сделано (хотя у меня есть догадки), синтаксис менее читаемым не становится.


А сейчас почему-то забыли.

Не забыл. Я просто понимаю, что этот ответ в данной ситуации неприменим, поэтому ищу другой.

Вопрос только в том, стремитесь вы его преумножать или уменьшать.

Естественно уменьшать, но когда заказчик меняет свое мнение по 3 раза за день и хочет все вчера, то вам придется иметь дело с говнокодом. И самый эффективный способ бороться с ним — декомпозировать и локализовать его.
Вот прямо всем? Я могу не особо напрягаясь найти вокруг себя много людей, занятых в бизнесе и разработке бизнес-приложений, которые SQL не знают (или знают на уровне «только что прочитал документацию»).

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

А остаток тогда атрибут товара/склада или как?
А что такое COUNT f(a,b) + g(a)? Там даже порядок выполнения операторов непонятен.

Тут я погорячился давайте просто f(a,b) IF h(a)=c.
От того, что я не знаю, зачем так сделано (хотя у меня есть догадки), синтаксис менее читаемым не становится.

Какие-то у вас двойные стандарты, но ладно.
Не забыл. Я просто понимаю, что этот ответ в данной ситуации неприменим, поэтому ищу другой.

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

Нет, нам придется искать себе другого заказчика, потому что это слишком дорог.


А остаток тогда атрибут товара/склада или как?

А остаток — свойство сущности "товар на складе". Или, в терминах графов, связи товар-склад.


Тут я погорячился давайте просто f(a,b) IF h(a)=c.

Эээ… это, типа, сложно? h(a) == c ? Some(f(a, b)) : None


Так он то как раз правильный, почему это он вдруг не применим

Потому что этот параметр нигде не определен (в отличие от математики).

Нет, нам придется искать себе другого заказчика, потому что это слишком дорог.

А есть те кто берут его, делают говнокодом и завоевывают рынок. Например как в свое время сделал 1С. А вы ищите себе богатых непритязательных заказчиков.
А остаток — свойство сущности «товар на складе». Или, в терминах графов, связи товар-склад.

Интересненько, а что это за такая странная сущность «товар на складе». Я знаю две сущности Товар и Склад. Интересно, а «человек на складе» существует? Или «поставщик в юрлице». Я что-то такого даже в c# вашем любимом не припомню.
Эээ… это, типа, сложно? h(a) == c? Some(f(a, b)): None

Я вообще COUNT f(a,b) IF h(a)=c имел ввиду.
Потому что этот параметр нигде не определен (в отличие от математики).

Тяжело конечно с вами, ладно, проехали.
А есть те кто берут его, делают говнокодом и завоевывают рынок.

Люди вообще делают много неприятных вещей, чтобы завоевать рынок. Это не значит, что я хочу и/или буду их делать. Каждый сам определяет, на какие сделки со своей совестью он идет.


Интересненько, а что это за такая странная сущность «товар на складе».

Добро пожаловать в мир DDD и агрегатов.


Я вообще COUNT f(a,b) IF h(a)=c имел ввиду.

Тогда объясните, что это должно делать. Я не знаю, как можно сделать "число функции".

Люди вообще делают много неприятных вещей, чтобы завоевать рынок. Это не значит, что я хочу и/или буду их делать. Каждый сам определяет, на какие сделки со своей совестью он идет.

Я бы тоже хотел жить в идеальном мире. Жаль его не существует.
Добро пожаловать в мир DDD и агрегатов.

Спасибо, но мне не надо еще костылей, меня уже одно их название пугает.
Тогда объясните, что это должно делать. Я не знаю, как можно сделать «число функции».

Число пар a и b для которых f(a,b) не NULL и h(a) = c. Хотя вы уже в другой теме прокололись, что я могу просто OR или ELSE из другой таблицы добавить и у вас уже проблемы будут.
Я бы тоже хотел жить в идеальном мире. Жаль его не существует.

Я же говорю: разница в том, что вы на этой мысли и остановились со словами "ну и хрен с ним", а мне все еще не все равно.


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

Ну то есть вы даже не знаете, что это такое, но оно вам уже не надо. Прекрасно.


Число пар a и b для которых f(a,b) не NULL и h(a) = c

a
|> filter (a => h(a) == c)
|> collect (a => b.choose(b => f(a,b)))
|> count

Хотя вы уже в другой теме прокололись, что я могу просто OR или ELSE из другой таблицы добавить и у вас уже проблемы будут.

Неа, это не имеет никакого отношения к этой дискуссии.

Я же говорю: разница в том, что вы на этой мысли и остановились со словами «ну и хрен с ним», а мне все еще не все равно.

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

Я не понимаю зачем мне лишние, да еще дырявые абстракции, мне объектов и функций хватает, математика и информатика 9-й класс.
a
|> filter (a => h(a) == c)
|> collect (a => b.choose(b => f(a,b)))
|> count

Что-то я не понял, а b и a это что за коллекции? Откуда вы их взяли? А если в задаче это числа или другие примитивы?
Неа, это не имеет никакого отношения к этой дискуссии.

Ок, тогда задача GROUP SUM IF f(a) THEN h(a) ELSE x(a). Все в разных таблицах.

Я не понимаю зачем мне лишние, да еще дырявые абстракции

Вы еще не знаете, что эти абстракции делают, но уже считаете их лишними и дырявыми.


Что-то я не понял, а b и a это что за коллекции?

Это имплицитные коллекции, взятые на ambient context. Мне лень писать allof<A> и allof<B>.


GROUP SUM IF f(a) THEN h(a) ELSE x(a).

a |> map (a => f(a) ? h(a) : x(a)) |> sum


Все в разных таблицах.

Этот код не оперирует понятием "таблица", поэтому это уточнение бессмысленно.

Немного занудства.

>> Домашняя команда — атрибут матча

Скорее атрибут места проведения матча. Закрыли стадион — и «атрибут матча» придётся поменять.

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

Я 6 лет уже пишу на плюсах, так же немного писал для себя на C#, Rust, Haskell. Знаю даже немного SQL (приходилось работать с MSSQL, MySQL и Postgres). Я прочитал статью, а так же все ваши комментарии. До сих пор ничего не понятно) А LsFusion выглядит просто максимально непонятным. Без подготовки, прочитать на нем ваще ниче не смог. Очень неинтуитивный язык. Даже Haskell мне проще дался.

А у нас люди, которые IT до этого видели только на картингах, через месяц уже реализовывали по 5 реальных задач в день.
Можно конкретнее что вам не понятно. Группировка, композиция? Вот эта штука понятна:
hostGamesPlayed(team) = GROUP SUM 1 IF hostTeam(game) = team.
Мне например Haskell мозг взрывает, ну и все эти |>. Мы такой синтаксис выбрали не с потолка, а именно эмпирически, таким образом чтобы людей было проще обучать. Возможно кому-то и иероглифы привычнее буквенных языков, но с точки зрения бизнеса приходится ориентироваться на среднестатистического человека.
>> Мне например Haskell мозг взрывает, ну и все эти |>

Скорее это проблема преподавателя. Точнее — автора той книги, по которой вы пытались учить Хаскель.

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

Я вам тоже самое про любой язык сказать могу. В том числе про lsFusion.
Да, это императивное программирование. Вопрос в соотношениях декларативности и императивности программирования. В различных диалектах SQL тоже есть императивное программирование, что не делает весь язык не декларативным.

Отдельное спасибо за то, что не просто рассказываете о крутизне платформы, но и выложили исходный код старых, крупных проектов, написанных на этой платформе.


Я правильно понял, что lsFusion код транслируется в SQL и хранимые процедуры?

Кстати, кто хочет сам потыкать:
git clone https://github.com/lsfusion-solutions/timetracking
mvn antrun:run -Pexec-client


Появляется GUI на свинге, дальше продвинуться не удалось — нужен какой-то сервер, причем, похоже, не сервер БД.

Собственно нужен сервер приложений. Для этого нужно конфигурацию в IDE создать и файл настроек, чтобы туда параметры подключения к Postgres прописать. Тут есть подробнее.
Лучше смотрите CRM. Там есть инструкция по установке в описании.
Я правильно понял, что lsFusion код транслируется в SQL и хранимые процедуры?

Логика свойств, логика изменений и вся логика представлений транслируется в SQL. Вообще общий принцип таков, если объектов больше чем несколько, все по максимуму выполнять на SQL сервере. Если какие то данные можно вычислять вместе, вычислять вместе, опять таки на SQL-сервере (в логике представлений это правило работает всегда, в логике действий есть нюансы, когда разные изменения выполняются разными запросами, но это касается только метаданных, данные всегда одним запросом — N+1 никогда не бывает)

Хранимые процедуры используются только для реализации рекурсий, так как у CTE очень много ограничений, в частности там например GROUP BY нельзя использовать, что очень критично для них.
UFO just landed and posted this here
Любое бизнес-приложение это прежде всего схема хранения данных, алгоритмы во многом вытекают из нее. Вы, я так понял, ориентируетесь на реляционную схему хранения и SQL, хотя существуют и другие варианты — деревья, графы, избыточные кубы, журналы событий наконец. Насколько ваш язык готов обрабатывать поток слабо-структурированных документов в реал-тайме, когда уже нет возможности вернуться на два шага назад, или сделать повторный запрос к хранилищу? А такие задачи бывают, особенно в распределенной среде.

Язык / платформа именно про работу со структурированными данными, и ее область применения сильно коррелирована с областью применения SQL. Практически все что вытянет SQL вытянет и lsFusion (то есть в какой то степени lsFusion можно рассматривать как следующее поколение SQL). Конкретно для обработки потока слабо-структурированных документов в реал-тайм, как и SQL, не сильно подходит.
2) Чем сложнее абстракция, тем обычно хуже с производительностью. Императивный многопоточный код + общее изменяемое состояние — обычно самый быстрый алгоритм именно потому, что соответсвует устройству «железа». Асиков для ERP пока не придумали. У меня к любой системе есть простой вопрос — время расчета и агрегирования 100 миллионов бизнес-объектов на обычном PC. Какие объемы и задержки были в ваших проектах? Это важно.

Опять-таки все упирается в возможности SQL-серверов, условно платформа накидывает сверху 20-30% оверхеда, но при этом за счет значительно более умного, а главное не такого оптимистичного оптимизатора (я сверху в комментах уже раза 3 в кратце упоминал что в него включено), позволяет сглаживать пики, и общая производительность становится а) более предсказуемой и б) в сумме увеличивается, за счет того что значительно уменьшается количество неэффективных запросов. Время расчета и агрегирования 100 миллионов бизнес-объектов опять-таки ограничено возможностями SQL-сервера (оверхеда в этом случае можно считать практически нет), но основной смысл в том чтобы не допускать этого (например материализациями, и тем что оптимизатор умеет везде проталкивать внешний контекст внутрь подзапросов). Хотя справедливости ради, для чистой аналитики даже мы сбоку всякие Qlik'и часто прикручиваем (хотя большую часть аналитики у многих клиентов делается средствами платформы, так как она значительно более гибкая, чем OLAP'ы).
UFO just landed and posted this here
Тут дело в другом, основной рынок РСУБД — это достаточно сложные ИС / бизнес-приложения, где данные получаются в различных срезах, в различных контекстах и в различных комбинациях, в таких запросах нужно очень много оптимизаций, а в NoSQL с этим все очень плохо. Собственно у SQL и NoSQL принципиально разные области применения, и для меня вообще загадка, как и зачем их люди пытаются сравнивать.
UFO just landed and posted this here
Четвертая статья цикла будет именно про ERP-платформы (в частности про 1С), и их все слабые места я на личном опыте очень хорошо знаю. Так что не переживайте, все будет :)
UFO just landed and posted this here
Почему не позволяет, позволяет.
Можно писать f(a) =… MATERIALIZED INDEXED;
и оно будет и материализовано и проиндексировано. Фишка OLAP, на самом деле в мультисрезах (то есть материализации под все комбинации) и много низкоуровневых оптимизаций именно под операции суммирования в этих мультисрезах. Но в простых случаях да можно считать, что материализация это обобщение OLAP (собственно поэтому в Разрабатывайте просто на сайте мы и указали на этот семантический разрыв между OLTP и OLAP, хотя из-за все тех же низкоуровневых оптимизация в OLAP в этом есть определенная доля лукавства).
UFO just landed and posted this here
Мы изначально и не создавали этот продукт для русскоязычного сегмента. Если бы речь шла только о нем, то как говорилось в одном культовом сериале: «There must be a lot more easier ways to steal», в том смысле, что создавать настолько архитектурно сложный продукт (а это было очень тяжело), для того чтобы конкурировать с 1С явно того не стоит.

Но раз предоставилась возможность протестировать рынок (пусть и в королевстве кривых зеркал), на узком локализованном сегменте, с возможностью лучше понимать все свои слабые стороны (а постсовок он такой — все новое воспринимается как риск, а не как возможность), грех ей не воспользоваться.
UFO just landed and posted this here
Он не умер, он стагнировал. Именно потому что я написал в начале статьи. То есть, если нет ничего нового за последние 15 лет, то и менять что-то нет смысла. Но когда ты приходишь на рынок, предлагая «быстро, дешево, качественно» одновременно, и сначала с moneyback'ом, а потом с восторженными рефами, то он оказывается не таким мертвым. Так из ТОП 15 сетей Беларуси мы только 5 за последние несколько лет перевели на эту платформу, и практически со всеми остальными за исключением может 3-4 в том или ином виде ведем переговоры.
UFO just landed and posted this here
Я так понимаю сайт вы тоже не нашли. Сейчас пишутся остальные статьи, там все будет, в том числе про 1С.

Но забегая вперед.
1. ORM — в бизнес-приложениях это скорее вред чем польза. Прежде всего из-за объектно-реляционного семантического разрыва. Который возникает в том числе из-за инкапсуляции. Ну и на больших объемах ORM ложится. Если вы посмотрите исходники того же управления торговлей, увидите что там все основные места жесткий лапшекод на временных таблицах и ручном формировании запросов на их псевдо-SQL. То есть сам 1С от ORM в своих решениях отказывается.

2. В lsFusion все еще круче там один механизм и для форм и для отчетов и для экспортов / импортов. Разработчики за час обучаются по сути всему сразу. Сейчас как раз пишу статью.

3. Зачем 1С делал свой синтаксис вообще загадка. У них не language-based платформа как скажем ABAP или lsFusion, им свой язык на фиг не упал. Но как видите им не сильно мешает. Много вы видели ERP-систем на java, c#?

4. Имеет, со всеми, причем lsFusion не как 1С просто транслирует синтаксис (а скажем в постгрес к примеру вообще не поддерживается predicate pushdown то есть SELECT A.x FROM (SELECT invoiceid, SUM(quantity) AS x FROM invoiceDetail BY invoice) A JOIN selectedinvoices B ON a.invoiceid = b.invoiceid благополучно положит всю базу), а именно компилирует и оптимизирует запросы (скажем selectedinvoices проталкивает внутрь, при этом делать это оптимизатор в lsFusion умеет в общем случае когда внутри и снаружи любые контексты, то есть в том числе UNION, GROUP и даже рекурсии)

5. Там Java действия в одну строчку подключается: myAction INTERNAL 'my.java.action', и наоборот сервер в любое Java Spring приложение в одну строку embed'ся через DI.

6. LGPLv3 лицензия прямо в третьем абзаце.

Вы меня конечно извините, но по вашему комментарию сложилось впечатление: «я Пастернака не читал, но осуждаю» (так как ответы на все вопросы можно получить либо в статье, либо в комментах, либо в пару кликов на сайте, хотя я понимаю, что вы абсолютно не обязаны это делать)
Еще один бизнес язык по типу 1С, C/AL, ABAP/4 и тому подобных
Я уже писал выше, но повторю:
Отличий очень много. Главное отличие, что lsFusion — это декларативный (как SQL, а не императивный) и функциональный язык. Те, что вы перечислили — классические императивные языки. Советую посмотреть, например, Турнирная таблица (там нету ни строчки императивного кода) и представить как его сделать на вышеперечисленных языках.

Но это действительно бизнес язык. Плюс все вышеперечисленные — проприетарные (что уже значительный минус).
Там на сайте есть сравнение, с ними всеми по пунктам. С общим скорингом. Но если не хотите ходить на посторонние сайты, не волнуйтесь, после технических пойдут продающие статьи, где все будет детально расписано по пунктам.
По поводу сравнения. До того, как у вас вышел LS Fusion, пересекался с вашей компанией. Тогда вы тоже активно сравнивали 1С с LS Trade. Результат сравнения был в пользу вашего продукта. Но с небольшим нюансом — сравнивалась файловая 1С 7.7 97 года выпуска и ваш продукт, с использованием MS SQL и в состоянии на 2011 год.

В 2019, вы сравниваете LS Fusion и 1С 8, но берете актуальную версию своей платформы и версию 8.2 платформы 1С (а, 1с 8.3, на минуточку, вышла в 2013 году), причем, судя по «экранные формы хранятся в бинарных файлах» еще и в режиме «неуправляемых» форм (что опять же — стандарт для 1С версий 8.1 и ниже).

Даже если сделать допущение, что в остальном сравнение абсолютно не предвзято и корректно, насколько можно ему доверять (это ведь как сравнивать современную Ubuntu и Windows 98, отмечая отсутствие поддержки SSD дисков и оперативной памяти выше 2 гигабайт)?
В 2019, вы сравниваете LS Fusion и 1С 8, но берете актуальную версию своей платформы и версию 8.2 платформы 1С (а, 1с 8.3, на минуточку, вышла в 2013 году), причем, судя по «экранные формы хранятся в бинарных файлах» еще и в режиме «неуправляемых» форм (что опять же — стандарт для 1С версий 8.1 и ниже).

Не совсем так. Там есть отдельная колонка для 1С < 8.2 с автоматическими блокировками и «неуправляемыми» формами и тогда 1С была ближе к RAD (условному Foxpro), и 1С >=8.2 (в том числе 8.3) с ручными блокировками и «управляемыми» формами, где 1С уже ближе к Axapta и .NET. Собственно именно во втором случае, 1С потеряло C в ACID из коробки и получило проблему с обращением сервера к клиенту. Хотя C в ACID и в первом случае по большому счету не было, так как требовало корректного отката транзакции из dead lock'ов и повторения транзакции, а не кидание ошибки.

«Экранные формы хранятся в бинарных файлах». А вот тут можно поподробнее, мне казалось, что конфигурация до сих пор хранится в бинарном виде, потому как как для обратного требуется как минимум наличие языка задания форм. Ну и вообще переход на модель «everything as a code». Они вроде как пытались сделать это в EDT, но это лечение симптомов, а не болезни, непонятно как можно работать в модели постоянного экспорта / импорта.

Извините, примеры, какие-то куцые, уровня школьного бейсика/паскаля, или 1С. А можно что-то более похожее на примеры для языков программирования, и без КАПСА в КЛЮЧЕВЫХ СЛОВАХ как будто ВСЁ ЕЩЁ 80ЫЕ?


Я думал что назвать в качестве примера для программы для сравнения языка программирования… О, мандельброт.


https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/mandelbrot-python3-5.html


Или любое другое с https://benchmarksgame-team.pages.debian.net/benchmarksgame/

А можно что-то более похожее на примеры для языков программирования, и без КАПСА в КЛЮЧЕВЫХ СЛОВАХ как будто ВСЁ ЕЩЁ 80ЫЕ?

При разработке грамматики (я понимаю, что не так много людей этим занимались), регистр ключевых слов важен для того, чтобы упрощать правила, и делать язык более «чистым»

Я думал что назвать в качестве примера для программы для сравнения языка программирования… О, мандельброт.

Давайте не сравнивать языки, предназначенные для абсолютно разных целей. Вы же не сравниваете 1С или SQL с Java или Python?

Первый раз слышу, что от КАПСА язык становится чище. Я понимаю, что это субъективщина, но я привык читать код как подобие языка.


Например, сравните вот это:


for key, value in somedict.items():
    if key.lower() in good_keys:
       return value

… с вашими примерами. Исключительно с позиции читаемости. Я понимаю, что субъективно, но от вашего синтакиса пахнет коболом, нафталином и домом престарелых.


И да, я предлагаю любой язык программирования сравнивать с языками программирования общего назначения. При том, что язык специального назначения может иметь специальные формы для специальных целей, общая вычислительная способность (способность описать произвольный алгоритм) у него должна быть не хуже. Иначе мы получаем язык на котором что-то сделать можно, а что-то С ПОМОЩЬЮ боли ПОТОМУ что так НАДО.

lsFusion — это не язык общего назначения. А именно язык для конкретной области — разработкой информационных систем. Это в явную указано в статье.
Если уж сравнивать, то логично сравнивать именно с SQL. Он из той же области и также декларативен. Там рекомендацией для ключевых слов являются именно большие буквы. И SQL также изначально придумывался для бизнес-пользователей, а не программистов. Видимо обычному человеку (не программисту) так читабельнее.

А обычному программисту (не человеку) оно омерзительно читать.

А SQL запросы вам тоже омерзительно читать? А формулы в Excel?

формулы в excel — очень, к счастью, они редко выходят за пределы sum()/...; А SQL в программе — это уже какой-то декаданс, вместо ORM. Если же вы про "sql руками", то руками на нём никто не пишет программы, а пишут однострочники. К однострочникам запрос другой, потому что они обычно не занимают экраны и экраны текста.

А SQL в программе — это уже какой-то декаданс, вместо ORM

ORM ложится на больших объемах. И здравствуй если не SQL, то HQL или 1С-QL.
А можно узнать что такое однострочники? А то я что-то отстал от жизни.

for user in $(cat data.txt); do 'echo "select user from users where id=$user"|psql ... |xargs -P 4 -I I foobar I;done

Ну вы же понимаете, что если вы так будете писать в сложных ИС (не просто CRUD) типа ERP, все ляжет очень быстро.

Однострочники пишутся руками в консоли один раз для выполнения конкретной задачи и после этого теряются в дебрях history. В этом они отличаются от программ, которые пишутся для многократного запуска.

в демо-примерах под пользователем admin можно посмотреть форму «Администрирование» >> «Интерпретатор»: в системах на базе lsFusion тоже можно запускать любые скрипты средствами языка на лету и в GUI
Если же вы про «sql руками», то руками на нём никто не пишет программы

я попросил бы. SQL еще нас всех переживёт и на нём пишут не только однострочники. Однако, полностью согласен с тем, что ПИСАТЬ КОД КАПСОМ при наличие IDE с подсветкой это не особо умно.

Особенно когда в другом комменте ссылаешься на то, что IDE что-то подсвечивает, чтобы было понятно (потому что из синтаксиса не понятно).

Так не вы пишите код капсом, а IDE ее пишет капсом. Зато вы можете использовать в именах все ключевые слова, а не называть переменные aclass и ainterface.
ну так код же пишут, для того, чтобы его читать. В моём понимании, возможность читать лоу кейс код гораздо более предпочтительна, чем возможность назвать переменную select
Select a.interface From (Select invoiceid, Sum(quantity) As sum From invoiceDetail By invoice) a Join selectedinvoices b On a.class = b.class
О, кстати, а если ключевые слова с большой буквы просто будут также раздражать будет? А то непонятна где эта грань раздражения.

Объективно у капса есть проблемы с восприятием человеком. Заглавные буквы не предназначены для записи слов целиком только ими, а потому имеют начертания, которые выделяют их среди обычных букв, но не среди друг друга. Именно это вызывает у многих отторжение.

Будет гораздо лучше, на мой взгляд разумеется.
А SQL запросы вам тоже омерзительно читать?

select name from sys.tables


Да нет, ок.

(
как будто ВСЁ ЕЩЁ 80ЫЕ?

Что-то мне показалось неуловимо знакомым...
На заре советской эпохи (1918-1921)

20 нояб. 2014 г. — … и терпеть, но Завтра мы построим Новый Мир, справедливый и честный, а Старый Мир — уничтожим и отринем его прах с наших ног".
)
Предыстрия ( с др.сайта):
За капс в коде меня сразу уволят — на полном серьезе и без шуток. Это пишу для тех, кто не работает в частных компаниях (работающих в основном на мейнстримовых языках) — те кто работает, и так знают, как к этому отнесутся коллеги, вынужденные читать Ваш код. Большой баг на продакшене простят — все ошибаются. Но за капс кранты сразу. Даже в тех компаниях, где не принят официальный гайд про стиль кода, это подразумевается. Т.е. даже если кто-то в крупных фирмах захочет использовать КП или Оберон — его за один капс выкинут — даже слушать вряд ли будут. Ну и месяц как минимум коллеги поприкалываются. В таких компаниях на многих языках пишут — но капс сразу будет всех выбешивать.


Q:
Например, сравните вот это:

for key, value in somedict.items():
    if key.lower() in good_keys:
       return value


… с…. Исключительно с позиции читаемости.


A:
FOR Key, Value IN SomeDict.Items()
  IF Key.Lower() IN Good_keys
     RETURN Value
  .
.


( на всякий: это достаточно условный язык)

И теперь встречный вопрос:
Всё же, хотелось бы услышать, что будет происходить в фирме,
чьи работники привыкли существовать в «режиме без капса»,
которой «досталась» кодовая база проекта на языке с ALLCAPS-ом ключевых слов?

Пусть это будет Clarion: реалистичный бизнес сценарий и интересный технологический момент с .app/.dct

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

Я хз, что тут всех так бесит капс, мне наоборот нравится (и нет, мне не 50, мне 26). Пишу на плюсах в основном)

Надо организовать клуб анонимных капсофилов. :)
Ответ в четвертом комментарии — очень много ключевых слов. В частности например нельзя будет sum использовать. И как тогда суммы инвойсов к примеру называть. Не, мы практически одним действием можем включить поддержку маленьких букв убив кучу слов, нам не жалко (может и сделаем такой мод в следующих версиях), но если у вас это основной вопрос, который возник в отношении этого языка, то даже с маленькими буквами вы вряд ли попадете в early adopters. :)

Извините, примеры, какие-то куцые, уровня школьного бейсика/паскаля, или 1С.

А можно увидеть пример хотя бы уровня Турнирной таблицы на бейсике/паскале или 1С? Итак тут жалуются что слишком сложный пример.

А почему sum — это ключевое слово? В приличных языках программирования это уже давно метод класса, ассоциированная функция или, хотя бы, просто функция из прелюдии, которую можно переопределять, если хочется.

Ну хотя бы потому что в SQL компилируется, и в SQL есть именно SUM, поэтому и там и тут это ключевое слово. Если честно Language vs Library сверху уже до винтиков обсудили.
тут жалуются что слишком сложный пример.

Я попросил бы. Пример сложный за счет языка, на котором он написан, это не собственная сложность задачи.

Ну покажите его же на .net. Или на любом другом языке. С ограничениями, логикой представлений и т.п. чтобы все на SQL выполнялось. Но вот чтобы прямо все, чтобы как в попробовать онлайн, скопировал, запустил. И чтобы там было хотя бы не в 3 раза больше строк кода. Про простоту вообще молчу.

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

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


Просто развлечения ради
type Team
{
  string Name
}

type IrregularWinType = OverTime | Penalties

type Game
{
  DateTime Date

  Team Host
  Team Guest
  Invariant DifferentTeams = Host != guest

  NonNegativeInt HostGoals
  NonNegativeInt GuestGoals
  Invariant NoTies = HostGoals != GuestGoals

  Team Winner -> HostGoals > GuestGoals ? Host : Guest
  Team Loser -> HostGoals > GuestGoals ? Guest : Host

  Maybe[IrregularWinType]  WinType
  Invariant OverwhelmingRegular = case abs(HostGoals - GuestGoals)
    | x when x >= 2 -> WinType == None
    | _ -> WinType == Some
}

def Host team game = game.Host == team
def Guest team game = game.Guest == team
def GamesPlayedAs pred team = filter (pred team)
def HostGamesPlayed team = GamesPlayedAs Host team
def GuestGamesPlayed team = GamesPlayedAs Guest team
def GamesPlayed team = GamesPlayedAs (g -> (Host team g) || (Guest team g))

def GamesWonBy team = 
  filter (g -> g.Winner == team)
  >> groupby (g -> g.WinType)
  >> dict

def GamesLostBy team = 
  filter (g -> g.Loser == team)
  >> groupby (g -> g.WinType)
  >> dict

def Points team games =
  (games |> GamesWonBy team)[None] * 3
  + ((games |> GamesWonBy team)[OverTime] + (games |> GamesWonBy team)[Penalties]) * 2
  + (games |> GamesLostBy team)[OverTime]
  + (games |> GamesLostBy team)[Penalties]

def GoalsScored team = 
  map (g -> g.Host == team ? g.HostGoals : (g.Guest == team ? g.GuestGoals : 0))
  >> sum

def GoalsConceded team = 
  map (g -> g.Host == team ? g.GuestGoals : (g.Guest == team ? g.HostGoals : 0))
  >> sum

def OrderTeams games = orderByDesc  (t -> (
  games |> Points(t),
  games |> GamesWon(t)[None],
  games |> GamesWon(t)[OverTime],
  games |> GamesWon(t)[Penalties],
  games |> GoalsScored(t) - GoalsConceded(t)
  games |> GoalsScored(t)
  ))

def TeamsWithPlaces games = OrderTeams games |> enumerate
Я чуть позже отвечу подробнее, хотя если честно я тут реально половину не понял, и я так понял всю логику представлений вы пропустили. Ну и надо было конечно пример УМП просить, там куда больше функций с двумя параметрами, и с ограничениями вы бы так просто не выкрутились, да и с dictами помучались. Но два вопроса

1. Вы думаете это реально проще и интуитивно понятнее?
2. Это все на sql сервере будет выполняться?
Вы думаете это реально проще и интуитивно понятнее?

Это реально проще. Про "интуитивно понятнее" — не знаю, интуиция у всех разная.


Это все на sql сервере будет выполняться?

Это всего лишь описание. Декларативное. Оно может выполняться там, куда его пошлет рантайм.


(в чем, собственно, и прелесть декларативных языков)

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


Я вообще пример на реальном языке / платформе просил привести, а не на сферическом коне в вакууме.

Я не знаю как проще, но я бы наверное одного из 100 смог бы обучить такому языку.

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


Я вообще пример на реальном языке / платформе просил привест

Это как-то изменит соотношение собственной и добавленной сложности в примере? Если есть код, чья сложность ниже вашего (при сохранении функциональности), значит, у вашего кода добавленная сложность больше. При этом второй код тоже может быть не идеальным — просто более простым.

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

Вот это и есть луддизм в чистом виде. Я понимаю, что с точки зрения разработчика это нормально (так меньше конкуренция), но с точки зрения бизнеса желательно чтобы 11 из 10 людей могли писать код для использования другими людьми. Понятно что так не будет, но чем больше тем лучше.
Это как-то изменит соотношение собственной и добавленной сложности в примере? Если есть код, чья сложность ниже вашего (при сохранении функциональности), значит, у вашего кода добавленная сложность больше. При этом второй код тоже может быть не идеальным — просто более простым.

Вы это к чему? Что лучше быть богатым и здоровым чем бедным и больным? Я знаю.
Вы когда кинули свою версию синтаксиса, что именно хотели показать? Что можно было использовать другой синтаксис и он проще. Мой опыт говорит что это не так, но посмотрим время покажет. Или все-таки что есть другой язык / платформа, который умеет то что умеет lsFusion? Ну тогда покажите его, но именно реальный язык, а не какой мог бы существовать.
Вот это и есть луддизм в чистом виде.

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


с точки зрения бизнеса желательно чтобы 11 из 10 людей могли писать код для использования другими людьми

Желательно. Но так не будет. Я знаю бизнес, которому желательно, чтобы 9 из 10 его сотрудников грамотно говорили по-английски, и этого все равно не происходит (а это проще, чем писать код).


Вы это к чему?

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


Вы когда кинули свою версию синтаксиса, что именно хотели показать? Что можно было использовать другой синтаксис и он проще.

Именно это.

Но так не будет

Поживем увидим. У нас пока локально удалось, посмотрим насколько это можно будет масштабировать.
К тому, что я не жаловался, что пример задачи сложный. Я говорил, что код сложнее, чем он мог бы быть.

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

господи, что вы к языку-то прикопались.
ну если вы можете написать такое описание — напишите кодогенератор из него в lsf, и будет вам счастье.

господи, что вы к языку-то прикопались

Потому что утверждения "наш язык лучше, потому что он декларативный, не то что" раздражают. Да и хвастаются именно языком.

Ну я не знаю кто делал такое утверждение, но точно не я. Синтаксис это грубо говоря пуговицы, я например в рамках этого проекта писал на ANTLR, GrammarKit, JFlex, groovy, NSIS, python, java, bash, javascript'е (это все разные языки) и меня это ни разу не напрягало, любой синтаксис я осваивал за 15 минут, особенно с поддержкой IDE. Я лично «хвастаюсь» парадигмой, а не синтаксисом языка (даже в документации мы их специально разделили). Более того даже не парадигмой, а тем что ее удалось реализовать в общем случае практически без ограничений, а это ОЧЕНЬ сложно.

Надо будет действительно возьмем ваш синтаксис и скомпилируем в наш, делов то. Фанаты ФП будут довольны, но пока они не наша основная фокус группа.
Декларативность это вообще не про синтаксис. Это про парадигму,
а точнее уровень абстракций в ней, насколько они высокоуровневые / эффективные.

А вы почему то язык ассоциируете с его синтаксисом, а не с абстракциями, которые он использует. Хотя синтаксис это на мой взгляд самая неважная часть языка.

Но кстати само это утверждение не совсем корректное. lsFusion — не функциональный язык, от слова вообще. В нем к примеру нельзя передавать ни свойства ни действия в качестве параметров.
А вы почему то язык ассоциируете с его синтаксисом, а не с абстракциями, которые он использует. Хотя синтаксис это на мой взгляд самая неважная часть языка.

А для меня как раз синтаксис — это то, с чем я буду иметь дело ежедневно, и если он неудобен, то язык будет меня тяготить.


Другое дело, что абстрации — это тоже вопрос. У вас вот нет ФВП, а это, как по мне, одна из самых важных абстракций при работе с данными.

А для меня как раз синтаксис — это то, с чем я буду иметь дело ежедневно, и если он неудобен, то язык будет меня тяготить.

Часто что-то кажется неудобным только по причине непривычности. И это ощущение обычно очень обманчиво.
Другое дело, что абстрации — это тоже вопрос. У вас вот нет ФВП, а это, как по мне, одна из самых важных абстракций при работе с данными.

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

Какая "более высокоуровневая абстракция" позволит мне эффективнее компоновать предикаты для запроса, чем ФВП?

Та, которая будет генерить запрос за вас :)

И если бы у вас не стояла задача ORM, вы реально считает что в ФВП его генерить эффективнее чем писать на самом SQL?
Та, которая будет генерить запрос за вас

ФВП в сочетании с деревьями выражений (и соответствующим фреймворком) это уже делают. Еще варианты?


вы реально считает что в ФВП его генерить эффективнее чем писать на самом SQL?

Да. В SQL весьма неудобно переиспользовать части запросов.

ФВП в сочетании с деревьями выражений (и соответствующим фреймворком) это уже делают. Еще варианты?

Речь шла о том, что вы скажем просто задаете форму как в Турнирной таблице, а запросы уже где-то сами генерятся.
Хотя если даже не касаться еще более высокоуровневых абстракций, задачу с 2* покажете как решать на ФВП?
Да. В SQL весьма неудобно переиспользовать части запросов.

Там есть VIEW, которые даже удобнее ваших ФВП.
Речь шла о том, что вы скажем просто задаете форму как в Турнирной таблице, а запросы уже где-то сами генерятся.

asp.net MVC + IQueryable-репозиторий. Работало десять лет назад.


Хотя если даже не касаться еще более высокоуровневых абстракций, задачу с 2* покажете как решать на ФВП?

Ответ уже есть в том же посте, где задача.


Там есть VIEW, которые даже удобнее ваших ФВП.

Правда? Покажите, как на view сделать следующее: объявить предикат "скидочный" (объект считается скидочным, если у него проставлено поле "скидка в процентах" или поле "скидочная кампания"), а потом применить это предикат в любом месте, где встречается такой объект (например, мы выбрали лучшие продажи за вчера, а теперь хотим выбрать из них скидочные).

asp.net MVC + IQueryable-репозиторий. Работало десять лет назад.

Машинный код. Работало 50 лет назад. Но статью про логику представлений как раз пишу, потом покажете как это на asp.net MVC можно сделать. Хотя на Турнирную таблицу уже бы посмотрел. Тут у меня на нее ушло минуты 2. Как с этим у ASP.NET MVC?
Ответ уже есть в том же посте, где задача.

И не правильный.
Правда? Покажите, как на view сделать следующее: объявить предикат «скидочный» (объект считается скидочным, если у него проставлено поле «скидка в процентах» или поле «скидочная кампания»), а потом применить это предикат в любом месте, где встречается такой объект (например, мы выбрали лучшие продажи за вчера, а теперь хотим выбрать из них скидочные).

Делаете VIEW: SELECT * FROM sku WHERE… логика скидки. А потом JOIN'ите его в запросах. Хотя да геморнее, но есть свои плюсы. Кстати, а как в .NET сливать деревья выражений? То есть написали мы одну функцию, потом вторую, и хотим их выполнить в одном запросе?
Как с этим у ASP.NET MVC?

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


Делаете VIEW: SELECT * FROM sku WHERE… логика скидки. А потом JOIN'ите его в запросах.

… и сохраняется, скажем, примененная ранее сортировка?


Кстати, а как в .NET сливать деревья выражений?

System.Linq.Expressions.Expression

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

Ну так давайте. В примере турнирной таблицы у меня на это ушло 2 минуты. А я еще туда фильтр могу добавить какой-нибудь веселый типа что сверху команды, снизу матчи этой команды:
FILTERS hostTeam(game) = team OR guestTeam(game) = team. У меня на это уйдет еще 10 секунд (специально засек время пока писал эту строку). То есть у вас есть тоже не больше 2.10 минут уйдет.
System.Linq.Expressions.Expression

Там какой то совершенно дурацкий пример. Можно на супер простом примере, показать:
x(b) = GROUP SUM f(a) IF h(a) = b
y(b) = GROUP SUM g(a) IF h(a) = b
EXPORT FROM x(b), y(b);
Ну так давайте.

"давайте" что? Ссылку на платформу, инструкцию по пользованию, обучающий курс? Нет, не могу.


Можно на супер простом примере, показать:

Я опять не понимаю, что делает этот код.

«давайте» что? Ссылку на платформу, инструкцию по пользованию, обучающий курс? Нет, не могу.

Напишите. У меня на это 2 минуты ушло. У вас на максимум 3 уйдет.
FORM MainFormSingle 'Турнирная таблица'
OBJECTS team=Team, game=Game
PROPERTIES(game) date, hostTeamName, hostGoals, guestGoals, guestTeamName, resultName, NEW, DELETE
PROPERTIES(team) place, name, gamesPlayed, gamesWon, gamesWonOT, gamesWonSO,
gamesLostSO, gamesLostOT, gamesLost, goalsScored, goalsConceded, points, NEW, DELETE
ORDER place(team)
FILTERS hostTeam(game) = team OR guestTeam(game) = team
;

Я опять не понимаю, что делает этот код.

Один считает сумму f(a) когда h(a) = b, второй тоже самое для g(a).
Собственно я вам записал этот же код на русском.
Напишите. У меня на это 2 минуты ушло.

@Html
.Grid<GameTableViewModel>()
.FilteredBy(v => v.Team)
)
Это что весь код? Прямо так можно запустить? При изменении любых данных форма реактивно будет обновляться? На SQL причем все?

Да, нет, да, нет.

У вас вообще-то FORM ... это тоже не весь код, есть еще движок, который это обрабатывает и превращает в HTML-код. Разницы никакой нет.

Весь код. Абсолютно весь, достаточно чтобы запустить.
А в MVC.net
нет

Там может за ширмой целый рояль стоит. Что например такое GameTableViewModel это в .NET такой класс есть?

Так и у вас точно такой же рояль. Я могу этот код запустить сразу в СУБД или там в браузере? Нет, нужен ваш движок.

Так и в СУБД без компьютера вы не запустите. И в браузере без ОС. Этот код можно запустить в платформе lsFusion, без какого либо дополнительного кода, на той же платформе что и у всех. А приведенный код в платформе .Net? То есть я сейчас поставлю себе .net скопирую этот код, запущу и что произойдет? Можно мне весь код, который точно заработает когда я скачаю .net с официального сайта. А пока это все смахивает на какой то троллинг.

Программа "Платформа lsFusion" имеет обработчик конструкции "FORM", который генерирует HTML-код, точно так же как приведенная программа имеет обработчик конструкции "@Html", который генерирует HTML-код. У вас на чем, на Java движок написан? Если я скачаю Java с официального сайта, ваш код заработает?


Вы написали обработчик языка и добавили встроенные компоненты. Некорректно сравнивать это с другой программой без встроенных компонентов. У вас есть генератор HTML-кода, соответственно и сравнивать можно с решением, где есть генератор HTML-кода. Этот код делается один раз и потом переиспользуется в разных проектах, так же как и у вас.

Издеваетесь? Еще раз человек использовал класс GameTableViewModel. Это что за класс? Он есть в .NET? Потому что с тем же успехом я могу сказать что в реакте эта задача делается одной строкой:

А обработчик вашей FORM есть в Java?)


Вообще, насколько я понимаю, в GameTableViewModel написано примерно то же самое, что у вас в PROPERTIES.

А обработчик class есть в C на которой Java написана? Причем тут это. Мы сравниваем платформу lsFusion и .Net.

Нет, мы сравниваем программу на вашем языке, котрая запускается на фреймворке со встроенными компонентами, с программой на языке C#, которая запускается на фреймворке со встроенными компонентами. В отношении именно этого кода "FORM" и "@Html" ни логически ни технически ничем не отличаются. Так как оба обрабатываются неким движком, который по ним генерирует HTML.

Мы сравниваем платформу lsFusion и .Net.

Нет, я не знаю, что с чем вы сравниваете, а мы сравниваем платформу lsFusion с другой платформой, которая написана поверх asp.net MVC. Я даже могу процитировать: "При наличии соответствующей платформы — ровно столько времени, сколько нужно на определение классов данных.".

Вообще, насколько я понимаю, в GameTableViewModel написано примерно то же самое, что у вас в PROPERTIES.

Именно.

Ну так приведите этот код, чтобы сравнить можно было. И заодно посмотреть, как он будет при изменении команды обновлять таблицу снизу.
Это что за класс? Он есть в .NET?

Как будто классы Team и Game есть в lsFusion.

Я вот не пойму. Вы реально не понимаете разницу, или просто троллите?

Правда не понимаю разницу. И то, и другое — объявленные пользователем тривиальные DTO.


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


.GridFor<Game>()
...
.Filter(fb =>
  fb.Control(
    html => html.SelectorFor<Team>(),
    (game, team) => game.HostTeam == team || game.GuestTeam == team)
  )
)
Ну так напишите весь код. Что это за стриптиз для бедных? Покажу колено и правый локоть.

Я привел весь код. И у меня на это ушло не больше 2 минут.

А что изменится-то от этого? Ну вот выпишу я десяток (или полтора) колонок вида Column(g => g.HostGoals), и что изменится?


Вот привел я вам в соседнем треде ответ на вопрос "как считается такое выражение" — и что?

Можно будет сравнить. А заодно мне интересно посмотреть на то как будет обеспечиваться реактивность, и понять как это внутри работает, а значит как будет работать на больших объемах.
Вот привел я вам в соседнем треде ответ на вопрос «как считается такое выражение» — и что?

Вы так и не привели, начали увиливать, что от провайдера зависит и т.п. Но не важно там простой кейс, а тут более жизненный пример (хотя и тоже еще очень далек от real-life задач как в ERP)
Можно будет сравнить.

Сравнить можно уже сейчас.


А заодно мне интересно посмотреть на то как будет обеспечиваться реактивность

Из декларативного кода вы это никак не увидите. Спойлер: никак.


и понять как это внутри работает, а значит как будет работать на больших объемах

Так же, как и любые другие операции поверх IQueryable.


Проще говоря, нет никакой разницы в том, как это будет работать "на больших объемах" по сравнению с тем, как работает на тех же объемах приведенный три дня назад декларативный код, который делает перечисление поверх последовательности — они работают одинаково, просто здесь добавляется отрисовка в HTML.

>Сравнить можно уже сейчас.
Не могу, вы отказываетесь приводить. Я его запустить не могу в частности.

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

Из декларативного кода вы это никак не увидите. Спойлер: никак.

Ну круто. То есть форма не реактивная получится. А мне пример реактивной можно увидеть?

Проще говоря, нет никакой разницы в том, как это будет работать «на больших объемах»

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

Того, что я привел, достаточно для сравнения. Если вы не можете мысленно размножить описание колонок, я не обязан это за вас делать.


Я его запустить не могу в частности.

А вы все равно не сможете. Вам будет нужна платформа, которой у вас нет.


хочу пример на .NET вставить

Я против того, чтобы вы вставляли мой код как пример.


А мне пример реактивной можно увидеть?

Нет. Мне надоело гоняться за вашими постоянно растущими требованиями.


Когда отправите в продакшн будет очень большая разница.

Вы мне рассказываете, какая будет "в продакшне" разница между двумя примерами моего кода?

Я привел весь код.

Так а где он весь-то? Из конструкции FORM разве можно понять, какой HTML-код генерируется, как обеспечивается реактивность и как это внутри работает?

Нет. Так мне и не надо. Мне ехать а не шашечки. И я хочу такой же код на .net увидеть причем желательно как и тут с реактивностью и работой на больших объемах.

Подождите. Если из вашего кода на языке lsFusion нельзя понять "как обеспечивается реактивность и как это внутри работает", почему вы требуете это от других? Я вот хочу попробовать на PHP ваш пример с турнирной таблицей написать, там тоже будет отдельно движок, отдельно код приложения. Почему вы в своем коде код и работу движка не учитываете, а в коде на других языках учитываете?

Один считает сумму f(a) когда h(a) = b, второй тоже самое для g(a).
Собственно я вам записал этот же код на русском.

a
|> filter (a => h(a) == b)
|> fold (((ff, gg), a) => (ff+f(a), gg+g(a)))

Ну или на выбор:


def x b = filter (a => h(a) == b) >> map f >> sum
def y b = filter (a => h(a) == b) >> map g >> sum

(a |> x b, a |> y b)
Когда некоторая ERP платформа придумывает свой язык это в 90% случаев попытка привязать к себе клиентов (а 10% просто желание разрабочиков ERP поиграться с созданием своего языка). Представим, что внутри 1С был бы язык вроде Java, C#, Pascal, разумеется клиентам проще было перейти на другую систему, они не покупали консультации, не обучали бы специалистов на тренингах, не появилась бы отдельная профессия 1С-программист и т.д.

И, разумеется, конкуренты этой ERP платформы никогда этот язык не будут использовать, а обычным программистам нафиг не нужно добровольно идти в company lock, используя этот язык в независимых проектах, если работодатель не использует эту ERP и за это не платит. Поэтому очень сомнительно будущее подобных языков за пределами собственных платформ.
Когда некоторая ERP платформа придумывает свой язык это в 90% случаев попытка привязать к себе клиентов (а 10% просто желание разрабочиков ERP поиграться с созданием своего языка)

У нас в реальности было желание лаконично и точно описывать сущности из придуманной концепции без лишнего синтаксического мусора. Альтернативой был fluent interface/eDSL, у нас что-то подобное было в самом начале (правда, не в лучшей реализации), но выбор пал на полноценный DSL. Я считаю, что то, что в результате проекты у нас сейчас реализовывают бизнес-аналитики, говорит о том, что такой выбор был довольно успешным. Во всяком случае, те из них, кто застал темные времена без DSL, вздрагивают, когда вспоминают, как приходилось кодировать раньше.
язык вроде Java, C#, Pascal

А что вы подразумеваете под языками? Синтаксис? Так у первых двух он вообще не свой, а от C++. И зачем, по-вашему, придумали SQL? Думаете лучше, чтобы вместо него языком для работы с РСУБД был C++ синтаксис?
Когда некоторая ERP платформа придумывает свой язык это в 90% случаев попытка привязать к себе клиентов (а 10% просто желание разрабочиков ERP поиграться с созданием своего языка)

А когда не существует языков с абстракциями платформы что делать? Пытаться натянуть сову на глобус, как тут предлагали в аналоге Турнирной таблицы на каком то языке ФП (я так и не понял что это за язык). Чтобы обычные люди себе мозг сломали?
Представим, что внутри 1С был бы язык вроде Java, C#, Pascal, разумеется клиентам проще было перейти на другую систему, они не покупали консультации, не обучали бы специалистов на тренингах, не появилась бы отдельная профессия 1С-программист и т.д.

Конечно… Java и C# программистов же так легко найти. И они такие дешевые, а эти 1С программисты совсем зажрались. И они будут решать задачи куда быстрее 1С программистов. Бизнесу фиолетово на каком языке пишут его решения. Ему нужно быстро дешево качественно. И любому бизнесу куда выгоднее, если он может взять человека с улицы и обучить его за месяц, чем найти человека на рынке из пусть даже 10000 человек, если этот рынок дефицитный (что сейчас по факту и наблюдается)
И, разумеется, конкуренты этой ERP платформы никогда этот язык не будут использовать, а обычным программистам нафиг не нужно добровольно идти в company lock, используя этот язык в независимых проектах, если работодатель не использует эту ERP и за это не платит. Поэтому очень сомнительно будущее подобных языков за пределами собственных платформ.

Если только платформа не существенно лучше остальных на рынке и не станет достаточно распространенной. То есть не создаст рынок. Собственно SQL отличный пример такого языка.
Поясните, а чем этот проект отличается от условного оракла со встроенным в него PLSQL и прочими расширениями?
Если вкратце, всем. Оракл вообще язык работы с таблицами, а не функциями. Для того, чем конкретно отличается можно подробнее посмотреть здесь.
Извините, я все же не понял.

Может я не до конца погрузился, но я увидел проект LsFusion как попытку соединить в одном месте декларативную обработку данных(аля SQL) и подходы от «обычных» ЯП(процедуры, функции, ООП).
Теперь я смотрю на Oracle и вижу на основе одного оракла:
0. БД в комплекте
1. Возможность работать с данными через SQL
2. Если SQL мало, то есть расширение SQL — PLSQL с функциями, процедурами и ООП(классы, объекты, наследование и вот это вот все)
3. Oraсle APEX для разворачивания Web интерфейса.

То есть Oracle решает все те же задачи, что и LsFusion только лучше(ну как мне пока кажется).
Наверное я все еще что-то не понял. Было бы интересно посомтреть о сравнении чегонибудь с Oracle: В LsFusion так, в Oracle так и примеры задач, которые в Oracle не решаются.

PS
Сравнительную табличку на половину не понял. Возможно ее следует снабдить пояснениями к тому, что подразумевается под каждым из пунктов.
Например пункт «Один язык работы с данными», написано, что у Оракла этого нет. Но вот же SQL — язык для работы с данными.
Сравнительную табличку на половину не понял. Возможно ее следует снабдить пояснениями к тому, что подразумевается под каждым из пунктов.
Например пункт «Один язык работы с данными», написано, что у Оракла этого нет. Но вот же SQL — язык для работы с данными.

Там можно на? нажать и она текст покажет. Плюс слева есть вкладка возможности и там есть ссылки на документацию и how-to. Что касается пункта один язык работы с данными, то SQL, а точнее PL/SQL (так как SQL это чисто логика вычислений) вообще не язык работы с функциями / объектами, а язык работы с таблицами / примитивами, то есть объектов там нет как класса. Что по сути означает что объекты нужно реализовывать где-то еще, или в PL или на клиенте и соответственно N+1 проблему вам придется решать руками. То есть если напишите (я не помню какой там конкретно синтаксис)
FOR i = 1 TO 10 DO
SELECT dff FROM a WHERE a.x=i
Вы получите 10 запросов. lsFusion такой разрыв ликвидирует автоматически (причем естественно не только в таком простом случае, а в куда более сложных), то есть такие вещи он будет выполнять одним запросом.
В LsFusion так, в Oracle так и примеры задач, которые в Oracle не решаются.

Там на самом деле их десятки (динамическая физическая модель, ограничения на любые view, trigger'ы на любые view, лицензия и т.п.), не говоря о том, что в Oracle логики представлений в принципе нет, не говоря уже про классы / наследование / полиморфизм, явную типизацию.
Но самое смешное что даже на его поле, возьмем материализованные обновляемые представления (MATERIALIZED FAST REFRESH VIEW):
в lsFusion можно любой показатель материализовать, даже с рекурсиями, даже с PARTITION ORDER. Причем реально эффективно и прозрачно. В Oracle видели в статье список ограничений на 3 страницы? Не говоря уже об эффективности работы этих view.
То есть если напишите (я не помню какой там конкретно синтаксис)
FOR i = 1 TO 10 DO
SELECT dff FROM a WHERE a.x=i
Вы получите 10 запросов


Написать так конечно можно, но зачем? Можно обойтись одним запросом без цикла и вычитать в коллекцию(BULK COLLECT).

не говоря о том, что в Oracle логики представлений в принципе нет, не говоря уже про классы / наследование / полиморфизм, явную типизацию.

В PLSQL есть классы, есть наследование, есть полиморфизм(в том числе динамический), а что под явной типизацией подразумевается я вообще не понял.

В общем, я запутался еще больше. Меня не покидает ощущение, что мы говорим про разные вещи или я недопонимаю чего-то базового. Я на досуге по подробнее посмотрю возможности вашего продукта, может разберусь.

Было бы очень интересно почитать статью сравнения с основными конкурентами(в том числе с Oracle, так как мы на нем часто строим ERP) на каких нибудь простых синтетических примерах
Написать так конечно можно, но зачем? Можно обойтись одним запросом без цикла и вычитать в коллекцию(BULK COLLECT).

Явно не имеет смысла. Но допустим у вас есть функция уже doSomething(sku). И вам ее нужно вызвать для 10 sku в какой нибудь временной таблице. Вам нужно либо переписывать логику doSomething еще раз с таблицей, или делать FOR table DO doSomething(table.sku) и получать 10 запросов.
lsFusion же умеет это все сам разбирать и компилировать в один запрос.
Было бы очень интересно почитать статью сравнения с основными конкурентами(в том числе с Oracle, так как мы на нем часто строим ERP) на каких нибудь простых синтетических примерах

Это будет в пятой статье цикла где-то.
Явно не имеет смысла. Но допустим у вас есть функция уже doSomething(sku). И вам ее нужно вызвать для 10 sku в какой нибудь временной таблице. Вам нужно либо переписывать логику doSomething еще раз с таблицей, или делать FOR table DO doSomething(table.sku) и получать 10 запросов.
lsFusion же умеет это все сам разбирать и компилировать в один запрос.


На вскидку кажется, что задача автоматического разбора и составление одного запроса совершенно не тривиальная вещь. У меня сходу не получилось придумать ничего годного. На примере того же Oracle, вот у нас есть псевдокод:
collection1 : коллекция на 2 тысячи элементов не по порядку:
collection2 : коллекция для результатов
for k in collection
loop
select x into d from table t where t.id = k
collection2[k]:= d
end loop


В какой запрос это в результате превратиться?(Повторюсь, элементы в коллекции не по порядку и between написать не получится)

К тому же, в том же оракле зачастую запросы все равно приходится тюнить хинтами, потому что сам оракл не справляется с построениями хороших планов.

То есть не получится ли в результате, что как только запросы которые надо преобразовывать чуть сложнее, то лучше бы вообще их не преобразовывали. И все придется докручивать напильником
В какой запрос это в результате превратиться?(Повторюсь, элементы в коллекции не по порядку и between написать не получится)

Грубо говоря в insert into col2 select from table t join col1 on t.id=col2.id.
К тому же, в том же оракле зачастую запросы все равно приходится тюнить хинтами, потому что сам оракл не справляется с построениями хороших планов.

Там много механизмов для борьбы с этим. Прежде всего нормальный predicate pushdown, а не пару частных случаев как в oracle.
Ну и например такая штука как materialize subqueries: платформа estimate'ит время выполнения запроса, если он превышено, таймаутит, затем делает скоринг подзапросов (по их вложенности, сложности и т.п.), выбирает какие материализовать (важно (!) что это все происходит после predicate pushdown'а, иначе можно лишние данные прочитать), материализует их во временные таблицы, по которым уже нормальная статистика, после чего выполняет основной запрос.
То есть не получится ли в результате, что как только запросы которые надо преобразовывать чуть сложнее, то лучше бы вообще их не преобразовывали. И все придется докручивать напильником

Это как раз причина, по которой требования к компилятору / оптимизатору запросов платформы были очень жесткие. Тут как Oracle, просто сказать вы пишите не правильные запросы, переписывайте / делайте хинты не прокатывало (хотя это не значит что разработчик не может управлять процессом, он это делает но на более высоком уровне например добавляя материализации, таблицы, индексы и т.п., в платформе можно вообще одним действием разложить все данные в несколько таблиц, а можно для каждого набора классов свою создать, для этого просто сервер приложений надо перестартовать, платформа сама все сделает). Но было очень важно чтобы все работало само из коробки, так как уровень абстракций в несколько раз выше чем в SQL. И это очень сложная архитектурная задача, и ее таки удалось решить хотя в это мало кто верил. В итоге сейчас люди которые пишут логику, о физике не думают вообще, это практически сразу идет в продакшн, а при этом все работает стабильно и на очень бюджетном железе. У нас кстати забавный случай был, когда мы у одного заказчика меняли систему на Оракле, и он начала спрашивать требование к железу, мы ему сказали сервер за условные 5К, и он очень удивился, так как поставщики предыдущего решение говорили. Как? Они же на Postgres, и им нужен будет сервер в 5 раз мощнее, а не слабее чем был :)
Такс. Сейчас я попытаюсь чуть упорядочить:
1. Я так понял, что по сути у вас ЯП, который должно быть быстро писать. В результате под капотом «любая популярная СУБД» и код из LsFusion в конечном итоге превращается все равно в SQL. Правильно?
2. Если первое верно, то для каждой СУБД отдельно SQL адаптируется? Например используются штуки Oracle, которых нет в других СУБД?
3. По большей части вы стараетесь вынести обработку данных в свою систему, и обрабатывать их внутри вашей системы, а не СУБД. Правильно?

Если я все это понял правильно, то вопрос оптимизации запросов никуда не девается. Ведь после того, как ваша система что-то там автоматически сгенерирует, оно все равно пойдет в условный Oracle, который без хинтов ваш запрос не скушает.
4. А какие у вас инструменты для оптимизации этих самых запросов на уровне физического обращения?

Теперь продолжим разбирать пример, т.к. я все еще ничего не понял.

Грубо говоря в insert into col2 select from table t join col1 on t.id=col2.id.


Я что-то не понял. В моем вопросе есть коллекция(в оперативной памяти), есть таблица. У вас тут какая то путаница, вставляется в ту же сущность, из которой идет запрос(col2). Предположу, что это опечатка, и должно быть on t.id=col1.id. Я и в оракле могу написать так же join с коллекцией.
Но это путает меня еще больше. На данный момент БД нет никакой таблицы с названием col1, откуда она возьмется?

Давайте я попробую переформулировать задачу более общим образом:
В оперативной памяти есть массив ID по которым я хочу выбрать что-то из СУБД и поместить снова в оперативную память для дальнейшей обработки.
Комментарием выше я написал псевдокод, которым бы сделал это в Oracle.

Напишите пожалуйста код, который сделает это в вашем продукте, и объясните как оно будет работать на более низком уровне, а то пока выглядит как магия. Для упрощения моего понимания предположим, что вы все еще используете как СУБД Oracle, если у вас нет какого то своего супер решения.

PS
Не понимаю, за что вас минусуют.
1. Я так понял, что по сути у вас ЯП, который должно быть быстро писать. В результате под капотом «любая популярная СУБД» и код из LsFusion в конечном итоге превращается все равно в SQL. Правильно?

Все что можно максимально превращается в SQL (логика свойств, изменений, представления). Если совсем нельзя или работа идет с одним объектом остается на сервере приложений.
2. Если первое верно, то для каждой СУБД отдельно SQL адаптируется? Например используются штуки Oracle, которых нет в других СУБД?

Да, SQL не очень сильно стандартизирован на самом деле, поэтому используются разные синтаксисы, а иногда целиком разные механизмы. Скажем в MSSQL для custom aggregate'ов приходить генерить код на c# и компилировать его :(. Или в MSSQL нельзя в хранимках выполнять динамический код (что нужно для рекурсий так как CTE не всегда справляется) и приходится для каждой рекурсии создавать отдельную хранимку (в Postgres и Oracle не надо)
Но те же аналитические функции есть во всех субд и они активно используются для тех же разбиений, упорядочиваний.
Хотя конечно для кроссплатформенности приходится ориентироваться на самую «не умную» СУБД — Postgres.
3. По большей части вы стараетесь вынести обработку данных в свою систему, и обрабатывать их внутри вашей системы, а не СУБД. Правильно?

СУБД используется как большая виртуальная машина, в который идет компиляция, как грубо говоря C преобразуется в машинный код.
Если я все это понял правильно, то вопрос оптимизации запросов никуда не девается. Ведь после того, как ваша система что-то там автоматически сгенерирует, оно все равно пойдет в условный Oracle, который без хинтов ваш запрос не скушает.

Да все СУБД вообще это большой набор эвристик причем почему то жутко оптимистичных. И запросы приходится формировать и выполнять так, чтобы обходить все эти подводные камни.
4. А какие у вас инструменты для оптимизации этих самых запросов на уровне физического обращения?

Про predicate pushdown но в общем случае я уже писал (и где-то даже вверху приводил пример, но если не знаете что это такое могу еще раз привести). Про материализацию подзапросов постом выше. Есть еще мощные оптимизации:
Например если нужно сделать GROUP LAST f(x) ORDER g(x), и по ORDER'ам есть нужные индексы то платформа пытается преобразовать это в такую штуку, собрать контекст снаружи запроса и сделать, что-то вроде:
SELECT (SELECT f(x) WHERE x=A.x ORDER BY g(x) LIMIT 1) FROM внешний контекст A
Тогда субд реально делает планы в которой она в nested loop бежит по индексу по g и делает ровно один read, а не как при использовании агрегирующей функции Last где для поиска предыдущего ей надо пробежать по всем значениям.
Я что-то не понял. В моем вопросе есть коллекция(в оперативной памяти), есть таблица. У вас тут какая то путаница, вставляется в ту же сущность, из которой идет запрос(col2). Предположу, что это опечатка, и должно быть on t.id=col2.id. Я и в оракле могу написать так же join с коллекцией.

Грубо говоря все коллекции больше какого-то количество загружаются во временные таблицы и работа с ними идет как с временными таблицами, чтобы потом выполнять по одному запросу вставляя туда JOIN'ы.
Там да опечатка col1 надо.
В оракле можете писать join'ы с коллекцией, но я уже приводил пример:
У вас уже есть doSomething с каким то сложным запросом логикой внутри (например UPDATE). Вам нужно выполнить эту логику n раз. Вам либо надо заново писать doSomething но уже с join'ом, либо в FOR'е выполнять но тогда будет n запросов.
lsFusion умеет сам инлайнить doSomething, а потом FOR превращать в JOIN'ы WHERE и т.п.

PS: похоже кому-то не нравлюсь, и он из принципа это делает, я конечно могу в ответ тоже самое делать, но по мне это детский сад какой-то.
SQL-подобный язык. Ок.

Что не понравилось у вас —
1) видимо вам совершенно неведомо выравнивание и одно действие в одной строке
Вместо
externalHTTP()  { 
    EXTERNAL HTTP GET 'https://www.cs.cmu.edu/~chuck/lennapg/len_std.jpg' TO exportFile; 
    open(exportFile()); 

    EXTERNAL HTTP 'http://tryonline.lsfusion.org/exec?action=getExamples' PARAMS JSONFILE('\{«mode»=1\}') TO exportFile; // фигурные скобки escape'ся так как используются в интернационализации
    IMPORT FROM exportFile() FIELDS () TEXT caption, TEXT code DO
        MESSAGE 'Example : ' + caption + ', code : ' + code;
        
    EXTERNAL HTTP 'http://tryonline.lsfusion.org/exec?action=doSomething&someprm=$1' BODYURL 'otherprm=$2&andonemore=$3' PARAMS 1,2,'3'; // передает в BODY url-encoded второй и третий параметры
}

можно же писать красивее:
externalHTTP()  { 
    EXTERNAL 
           HTTP 
           GET 'https://www.cs.cmu.edu/~chuck/lennapg/len_std.jpg' 
           TO exportFile; 
    open(exportFile()); 

    EXTERNAL 
            HTTP 'http://tryonline.lsfusion.org/exec?action=getExamples' 
            PARAMS 
            JSONFILE('\{«mode»=1\}') 
            TO exportFile; // фигурные скобки escape'ся так как используются в интернационализации
    IMPORT 
            FROM exportFile() 
            FIELDS () 
            TEXT caption, TEXT code 
            DO
        MESSAGE 'Example : ' + caption + ', code : ' + code;
        
    EXTERNAL 
           HTTP 'http://tryonline.lsfusion.org/exec?action=doSomething&someprm=$1' 
           BODYURL 'otherprm=$2&andonemore=$3' 
           PARAMS 1,2,'3'; // передает в BODY url-encoded второй и третий параметры
}


2) У вас слишком много слов состоящих из заглавных букв.
И раз это уже устоявшаяся практика, а выглядит код как из конца 80-х, начала 90х — лучше добавить синтаксического сахара.
Например, двоеточие — как аппер-кейсер для зарезервированных слов.
Внедрение минимально по затратам.
Это даст возможность выглядеть коду как в 21м веке и не поломает старую традицию для желающих и сохранит полную обратную совместимость.
Так предыдущий код будет выглядеть так:
externalHTTP()  { 
    :external 
           :http 
           :get 'https://www.cs.cmu.edu/~chuck/lennapg/len_std.jpg' 
           :to exportFile; 
    open(exportFile()); 

    :external 
            :http 'http://tryonline.lsfusion.org/exec?action=getExamples' 
            :params 
            :JsonFile('\{«mode»=1\}') 
            :to exportFile; // фигурные скобки escape'ся так как используются в интернационализации
    :import 
            :from exportFile() 
            :fields () 
            :text caption, :textT code 
            :do
        :message 'Example : ' + caption + ', code : ' + code;
        
    :external 
           :http 'http://tryonline.lsfusion.org/exec?action=doSomething&someprm=$1' 
           :bodyURL 'otherprm=$2&andonemore=$3' 
           :params 1,2,'3'; // передает в BODY url-encoded второй и третий параметры
}

То есть ":external" должно исправлять на «EXTERNAL», но не должно исправлять ":exxxternal" на «EXXXTERNAL»
Спасибо за конструктивный комментарий. Пункт два действительно можно реализовать в таком или похожем виде, будем обсуждать.
Есть проще способ сделать как sql поддержать маленькие и сделать возможность имена в "" указывать, скажем «sum».

Хотя в любом случае эти вопросы к большим буквам и синтаксису конечно забавляют. Это как вы показываете людям первый самолет. Они ходят по нему, ходят, а потом: у вас кресло не так откидывается. Естественно у вас вопрос: смотрите крылья, реактивный двигатель, он летает. Ответ: я в этом ничего не понимаю, и вообще он сейчас стоит на земле, но зато в креслах я разбираюсь, у меня такие же в машине, так вот почему оно не так откидывается?
Странное сравнение.
Когда мне показывают самолёт, а я спрашиваю — ТАБУРЕТКИ?!
И для пилотов и для пассажиров?
Вы — да, но посмотрите какие крылья!…

Не покупают Феррари, если он выглядит как Запорожец, даже если под капотом Феррари.

Если по сути — разрешить прописные зарезервированные слова и кавычки для переменных — можно, хотя этим вы создаёте
А) неопределённое поведение. Так как «sum» — это переменная sum или это строка «sum»?
Б) обратную несовместимость. Так как старая программа в новом синтаксисе «sum» будет пытаться делать переменную, sum вместо переменной будет видеть зарезерованное слово
Странное сравнение.
Когда мне показывают самолёт, а я спрашиваю — ТАБУРЕТКИ?!
И для пилотов и для пассажиров?
Вы — да, но посмотрите какие крылья!…

Не покупают Феррари, если он выглядит как Запорожец, даже если под капотом Феррари.

Если бы в первом самолете даже лежа надо было лететь, все равно на нем полетели бы, потому как всего 3 часа лететь, по сравнению с 2 дня ехать пусть и с бОльшим комфортом. Другое дело, что да первым было бы стремновато в воздух подниматься, и не из-за табуреток.
Если по сути — разрешить прописные зарезервированные слова и кавычки для переменных — можно, хотя этим вы создаёте
А) неопределённое поведение. Так как «sum» — это переменная sum или это строка «sum»?
Б) обратную несовместимость. Так как старая программа в новом синтаксисе «sum» будет пытаться делать переменную, sum вместо переменной будет видеть зарезерованное слово

А) Так уже SQL делает и как-то живее всех живых. А хотя понял ваш вопрос. Кавычки одинарные — строковые литералы. А какие нибудь другие кавычки — идентификаторы.
Б) Обратная совместимость также как и во всех других языках делается — language level'ом (иначе языки в принципе не смогли бы новые ключевые слова вводить).
Если бы в первом самолете даже лежа надо было лететь, все равно на нем полетели бы, потому как всего 3 часа лететь, по сравнению с 2 дня ехать пусть и с бОльшим комфортом

Не переусердствуйте. Компании других стран, кроме Беларуси, как-то без вашего продукта выживают и живут припеваючи.
Обратная совместимость также как и во всех других языках делается — language level'ом

Тут дело ваше.
Я лишь акцентирую внимание на том, что вы, возможно, недооцениваете негативное влияние обратной несовместимости.
Переходят на новую версию лишь активно-развивающиеся проекты.
Остальные — либо замораживают обновлять ваше программное обеспечение, либо, что ещё хуже для вас — выкидывают и закрывают проект на вашем языке и заказывают себе другой продукт.
Например, из-за большой обратной несовместимости Питона2 и 3 переход длится уже десятилетие и никак не закончится. Приходится поддерживать 2 ветки языка.
Не переусердствуйте. Компании других стран, кроме Беларуси, как-то без вашего продукта выживают и живут припеваючи.

Не поверите, но до появления самолетов, люди ездили на автомобилях и тоже выживали и думали что живут припеваючи. А еще до этого на лошадях.
Тут дело ваше.
Я лишь акцентирую внимание на том, что вы, возможно, недооцениваете негативное влияние обратной несовместимости.
Переходят на новую версию лишь активно-развивающиеся проекты.
Остальные — либо замораживают обновлять ваше программное обеспечение, либо, что ещё хуже для вас — выкидывают и закрывают проект на вашем языке и заказывают себе другой продукт.
Например, из-за большой обратной несовместимости Питона2 и 3 переход длится уже десятилетие и никак не закончится. Приходится поддерживать 2 ветки языка.

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

Извините, но это голосновно.
В чём выигрыш?
В строках кода? Тогда давайте листинги одного и того-же в студию — будем сравнивать.
В производительности? Давайте цифры в студию по тестовым данным.
В чём-то другом? В студию!

Лично на мой свежий взгляд, ваш язык — SQL-подобный синтаксис среднего языка программирования.
Я вижу лишь одну фишку — ваш язык похож отдалённо на ЕРП-языки(типа 1С) для легкого перехода на ваш продукт.

Если судить по комментарием, большинство тоже не увидело ничего революционного.
Так что бремя доказательства революционности лежит на вас.
Извините, но это голосновно.
В чём выигрыш?
В строках кода? Тогда давайте листинги одного и того-же в студию — будем сравнивать.
В производительности? Давайте цифры в студию по тестовым данным.
В чём-то другом? В студию!

Тут у нас было два варианта, либо сразу дать цифры, тогда это просто назвали бы маркетинг-булшитом. Либо сначала дать техническое описание, а потом только цифры и сравнения. Мы решили пойти по второму пути.
Если судить по комментарием, большинство тоже не увидело ничего революционного.
Так что бремя доказательства революционности лежит на вас.

Большое видится на расстоянии. А тут пока небольшая часть, и целиком картина у большинства и не может вырисоваться (хотя кстати есть кто сразу въехал, но они почему-то решили напрямую связываться). Так что, just wait a little bit.
Тут у нас было два варианта, либо сразу дать цифры, тогда это просто назвали бы маркетинг-булшитом. Либо сначала дать техническое описание, а потом только цифры и сравнения.

Увы, но вы саме себе противоречите. Заголовок статьи прямо говорит — ваш язык «не очередной». Но в самой статье — лишь об ОЧЕРЕДНОМ SQL-подобном синтаксисе.

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

Это нормальный подход на самом деле, так иногда создаются прорывные вещи, но его проблема следущая, теперь ВАМ будет трудно заставить других людей разобраться в вашем языке. Ведь вся терминология своя собственная.

Сила же в том, чтобы говорить на общем языке, например «представляем вам язык общего назначения на базе JRE с глубокой интеграцией с Postgres и декларативными элементами в синтаксисе.» Сразу всё ясно.

Мы бы с удовольствием использовали какой-нибудь готовый язык, если бы в нем была хотя бы часть абстракций lsFusion. Но к сожалению таких нет. И использование уже готового синтаксиса если и было бы возможно, было бы натягиванием совы на глобус. Собственно тут кто то уже пытался использовать чужой синтаксис, и выглядело это очень чужеродно на мой взгляд.


Я понимаю все проблемы с продвижением новых языков, но если у SQL это получилось (а это ОЧЕНЬ не стандартный язык), то значит это не невозможно.

Занятная штука, здорово что находите время так обстоятельно и конструктивно «работать с возражениями». Присоединюсь к мнению, что синтаксис и гуй чисто визуально действительно весьма олдскульные, хотя это конечно дело привычки, но всё-же мне кажется современный веб интерфейс будет в каком то не сильно отдаленном будущем the must, хотя я конечно не специалист по миру ерп, возможно там это ок, да и дело наживное.

Интересует вопрос — а как вы работаете с миграциями? Накидали кода, развернули сервак, бабах — перименовали в коде кучу свойств, как оно потом всё это обрабатывает?

Интересует вопрос — а как вы работаете с миграциями? Накидали кода, развернули сервак, бабах — перименовали в коде кучу свойств, как оно потом всё это обрабатывает?

Если вкратце, то у нас есть миграционные скрипты, в которые при переименовании, например, свойств/действий из IDE будут автоматически вставляться строки миграции. Вообще, вопрос правильный, и в направлении миграции у нас еще есть что улучшать, потому что, если вы вдруг захотите переименовать все классы и/или переразбить их на другие пространства имен, то сделать это будет не так просто.

Более подробно можно прочитать здесь
Ок, спасибо, понятно. Т.е. я так понял часть работы по приведению схемы бд к коду выполняет платформа, а то, что автоматически невозможно — надо вручную прописывать в миграциях? Эх, никакой магии, жалко :)
Когда вы создаете / удаляете первичные свойства, таблицы, указываете явно таблицы для свойства, создаете / удаляете новые материализации / индексы и т.п. все само.

Но вообще говоря по старой и новой версии кода теоретически нельзя угадать, что если в старом коде было f и g, а в новом h и k, кого в кого надо переименовать.
Но вообще говоря по старой и новой версии кода теоретически нельзя угадать, что если в старом коде было f и g, а в новом h и k, кого в кого надо переименовать.

факт, собственно интересно как именно с этой проблемой на разных платформах справляются. Ибо именно переименование — какая то прям магическая операция, не позволяющая полностью миграции автоматизировать.
Ну если на уровне IDE поддерживается генерация миграций, то тоже не так напряжно. Нажал shift f6 и забыл. Когда будет следующее обновление платформа просто увидит не примененную миграцию и применит ее.

На самом деле самая жесть у СУБД с не транзакционным DDL (типа Oracle), там конечно обновление очень неприятная штука, так как упадет в середине, приходится руками разгребать, что обновилось, что нет.
Занятная штука, здорово что находите время так обстоятельно и конструктивно «работать с возражениями». Присоединюсь к мнению, что синтаксис и гуй чисто визуально действительно весьма олдскульные, хотя это конечно дело привычки, но всё-же мне кажется современный веб интерфейс будет в каком то не сильно отдаленном будущем the must, хотя я конечно не специалист по миру ерп, возможно там это ок, да и дело наживное.

Там мы сам рендеринг мы на react скорее всего переделаем, типа этого. Хотя старые тоже гуи оставим. Ну и конечно не думал, что большие буквы вот прям настолько некоторых раздражают.

Вы вот делаете компиляцию своего языка в SQL и пытаетесь выполнять его в субд. То есть тянете исполнение кода приложения поближе к данным. Вы не думали действовать в обратном направлении и тянуть данные поближе к приложению? Например, вы могли бы встроить в ваше приложение например OrientDB — встраиваемую графовую распределённую субд. Это позволило бы вам прямо из вашего приложения на Java, Kotlin или даже вашего кастомного языка, очень быстро траверситься по графу безо всяких predicate-pushdown.

Нет. Потому что как минимум не вытянуло бы производительности (насколько в OrientDB мощный оптимизатор запросов?). Не говоря уже о том, что как в OrientDB join'ами, группировками, аналитическими функциями, рекурсиями, ACID и всем остальным?
Это позволило бы вам прямо из вашего приложения на Java, Kotlin или даже вашего кастомного языка, очень быстро траверситься по графу безо всяких predicate-pushdown.

Это если у вас примитивная логика. А если у вас расчет показателя из 25 операторов группировки, суммирования, композиции и т.п. Кто будет строить эффективный план выполнения расчета таких показателей? Это не говоря уже про инкрементальность, например как там материализацию такого показателя сделать, если он редко изменяется, но часто читается (MATERIALIZED / INDEXED VIEW в SQL)?
Ну по тому, что я там прочитал, оптимизатора там по сути нет. То есть предлагают чуть ли не руками индексы использовать. Hash join'ы видимо тоже, но может я просто не нашел про это.

Там данные хранятся так, чтобы ни джойны, ни их оптимизаторы не требовались.

UFO just landed and posted this here
Тут ругались на капс — подумалось, что если будет шрифт где капс не такой большой как обычно, то это может выглядеть неплохо.
Тут дело в том что, в части случаев мы не контролируем шрифт. Как например в той же IDEA. И даже если плагином это удастся сделать, выглядеть все равно вычурно будет.

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

NitroJunkie, назрел один вопрос, каким образом обеспечивается целостность данных при одновременном редактировании? Демо система работает по принципу побеждает последний.

Родными средствами СУБД. Уровень изоляции повышается до Repeatable Read (можно и Serializable в Postgres, но там масштабируемость сильно просесть может), а дальше платформа отлавливает update conflict'ы и перестартует транзакции автоматически (пользователь этого не видит). Ну и там есть еще небольшая магия с sleep'ами чтобы deadlock'и разруливать (но это отдельная тема) и проверка классов (по сути удалением объектов) перед началом транзакции.

Тут правда есть нюанс, что RR в версионнике сильно понижает целостность до уровня что 100% гарантируются только материализованные данные (здесь подробнее). Но тут как раз очень сильно помогает механизм прозрачных материализаций. Соответственно можно просто добавить материализации данных, для которых нужно обеспечить целостность, и они станут целостными автоматически. На практике же, так как материализации используются также и для оптимизации производительности, обычно их количества уже по умолчанию достаточно чтобы обеспечить целостность из коробки.

Или вы что-то другое имели ввиду?

NitroJunkie, с Repeatable Read понятно, у меня вопрос немного другой. Допустим в модели есть свойство Name и два пользователя одновременно изменяют это поле. Пример урощенный, это могут быть и списки и еще что-то. В большинстве систем первому удастся сохранить, а вот второй пользователь получит ошибку, мол данные обновились, оптимистик лок. Я проверил у вас на демо и похоже всегда побеждает последний, каких-либо предупреждений при этом не выводится и возникает ситуация когда чужие изменения могут быть затерты непреднамерено.


В связи с этим второй вопрос как работает сохранение, сохраняется дельта или вся запись обновляется или еще более сложный вариант?


И еще вопрос, как работают более сложные процессы, где откат и повтор транзакций слишком дорогой, например, при обновлении большого числа записей?

возникает ситуация когда чужие изменения могут быть затерты непреднамерено.

Вы немного путаете. Непреднамеренно они затерты быть не могут, потому как lsFusion не объектно-ориентирован и не загружает объект целиком в память как тот же 1С. То есть если даже один пользователь поменял одно поле в одной строке, а другой пользователь поменял другое поле в этой же строке, то изменения обоих благополучно запишутся. А именно это проблема классического ORM, когда два пользователя открыли документ, один изменил в одной строке, другой в другой, и изменения одного пропали. И именно для этого нужны все эти предупреждения. Если же два пользователя меняют одно и то же значение, то смысла в описанных вами проверках мало, так как пользователю как правило все равно с (!) какого значения он меняет, если он хочет 5 он введет 5, и как правило ему все равно до было 3 или 1.

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

На самом деле в таком случае процесс уходит в «бесконечный» update conflict (например до вечера, когда нагрузка спадет, ну или ему сильно повезет днем). Но что важно, что при этом он оперативной работе базы практически не мешает (в этом сила версионников и почему они «победили» блокировочники).

Соответственно, на практике просто рубят транзакцию на блоки, и делают промежуточные APPLY (понятно что при этом надо учитывать, что целостность операции может уменьшаться).

NitroJunkie, я понимаю о чем вы говорите и уточню вопрос еще немного.


Пользователи работают с одной записью, скажем товар или какой то ряд из справочника. Оба они меняют одно и то же поле, например, Имя. Пусть начальное значение имени "Соль". Первый пользователь меняет имя на "Сахар", все хорошо, он видел верное предыдущее значение "Соль" и заменил его новым осознанно. Второй же пользователь видел устаревшее значение "Соль" и переписал его на "Хлеб", при этом результат работы первого пользователя он пропустил, то есть он даже не узнал, что отменил работу первого пользователя.


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

Пользователи работают с одной записью, скажем товар или какой то ряд из справочника. Оба они меняют одно и то же поле, например, Имя. Пусть начальное значение имени «Соль». Первый пользователь меняет имя на «Сахар», все хорошо, он видел верное предыдущее значение «Соль» и заменил его новым осознанно. Второй же пользователь видел устаревшее значение «Соль» и переписал его на «Хлеб», при этом результат работы первого пользователя он пропустил, то есть он даже не узнал, что отменил работу первого пользователя.

Я тоже понимаю о чем вы говорите :). И вы же я надеюсь тоже понимаете, что описанная вами ситуация надуманная. По идее оба пользователя будут менять название на Сахар. Ну или один из них вредитель, но он поменяет название на Хлеб в любом случае. То есть если пользователь считает что этот товар Сахар, ему все равно как он назывался до (Соль или Хлеб).

Вообще ORM делают эти проверки не для таких случаев, а чтобы соседние изменения не затирались.

В принципе можно и в lsFusion такой механизм реализовать, но там другой нюанс возникает. В lsFusion все списки динамические, то есть тот же документ читается не целиком, а как и остальные данные по частям (то есть только видимая часть). Это позволяет открывать большие документы мгновенно плюс значительно уменьшать нагрузку на сервера (как memory footprint так и нагрузку по сети), собственно то для чего и нужны динамические списки. И соответственно возникает вопрос на какой момент считать данные актуальными. По сути это надо делать на момент скроллинга, что немного не интуитивно понятно. Ну и в любом случае все это дело это значительный оверхед, а выигрыш не понятен (во всяком случае у нас больше полусотни крупных проектов из различных областей с суммарно >10к пользователей, и нам выносят мозг по любой мелочи, но с такими проблемами никто не обращался).
Например, в какой-то список могут быть дважды добалены элементы с одинаковым именем, хотя бизнес логика может быть к такому не готова.

А вот это из другой оперы. Тут как раз вы делаете:
xById = GROUP AGGR x BY id(x) MATERIALIZED;
И update conflict'ы вам не дадут создать два элемента с одинаковым id ни в каком случае. То есть один из пользователей сохранит изменения, второй получит update conflict на записи xById, а при повторном проведении выдастся constraint (который неявно создается в GROUP AGGR) что уникальность нарушена.