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

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

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

Хочу рассказать про некоторые моменты, которые стали понятны в этом процессе — может, вы передумаете делать свой DSL ????

Это ссылка на статью на Habr с описанием проекта и с чрезмерным количеством смайликов

Картинка таблички для примера:

Зачем может быть нужен DSL (domain-specific language)

Ситуация двойственная. Если бы я был программист — однозначно выбрал бы JS или Lua, или что-то известное. Но я не программист. У меня, вроде как, инженерное образование и реально программировать я не умею. То, что на VB писал в институте, чтоб руками не считать задачки по сопромату — это не в счет.

Если мне сказать: «а теперь надо выучить JS», я наверное оставлю это дело. А если сказать: «ну так здесь язык то и не язык вовсе, а такое что-то типа формул, да еще и ориентированный на непрограммистов» — я наверное попробую.

Во вторых, если вы делаете заточенный под приложение DSL, то эффективность использования приложения растет. За это вы платите усилиями на обучение пользователей. Но если подумать, то у Nginx свой язык конфига и у Apache тоже. В CI/CD инструментах тоже и так много где — те все-равно пользователям придется читать даташит.

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

Конечно, здесь не идет речь о языке широкого назначения — я рассказываю про DSL для конкретного приложения.

Перед тем как приступать

Выбрал я разрабатывать синтаксис. Может, это и было печальным решением с коммерческой точки зрения, но сейчас, когда сделанных не нем проектов стало больше 100, я решил немного рассказать, каким образом мы этот Totum-code придумывали. Может, кому-то, кто разрабатывает свой DSL, будет интересен наш опыт.

Опыт здесь такой — если вы идете в DSL, то до момента его шлифовки все печально. И этот период длится довольно долго, у нас он занял 3 года. Но зато потом, вроде, ниче.

Что у нас получилось в итоге

Что-то типа этого:

// Вызываем Ю-кассу из Totum-code:

=: getFromScript(uri: str`"https://" + $store_id + ":" + $store_key + "@api.yookassa.ru/v3/payments"`; headers: $headers; posts: $post)
    store_id: "034942"
    store_key: "test_HUoYJ_cyBhB"

headers: listCreate(item: str`"Idempotence-Key:" + $idempotence`; item: "Content-Type:application/json")
    idempotence: numRand(min: 1000; max: 10000)

post: jsonCreate(data: $post_row)
    post_row: rowCreate(field: "amount" = $amount; field: "capture" = true; field: "confirmation" = $confirmation)
        amount: rowCreate(field: "value" = #total; field: "currency" = "RUB")
        confirmation: rowCreate(field: "type" = "redirect"; field: "return_url" = "https://ru.totum.online")

Или этого:

= : #h_json[[firstLevel_2]][[secondLevel_Date]][$single] * $count

single: $key[0]
	key: listSearch(list: #h_json[[firstLevel_2]][[secondLevel_3]][[id]]; key: "value" = 11)
  
count: listCount(list: $list)
	list: selectList(table: $#ntn; field: 'id')

С правильной подсветкой читается намного лучше :)

Что я могу про это рассказать

Всегда думайте о том, как вы будете потом обучать других людей

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

Придется быть диктатором

Командная разработка языка на первых этапах – это зло.

Для того, что бы уменьшить количество исключений, надо представлять себе всю систему целиком, во всех вариантах работы одновременно. Т.е. надо запихнуть всю систему в одну голову, разом. Что?!

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

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

Начинайте с чего-то совсем простого и знакомого

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

Я подумал, что раз в интернетах активно используется # как обозначение тега, то его и будем использовать — #field_name и получаем вместо него значение этого поля.

Удаляйте лишнее

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

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

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

Например:

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

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

Оставили одни скобки — которые обозначали функцию: listSum(list: $list).

Почему круглые? Просто, фигурные сложно читаются.

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

Откладывайте непонятное, добавляйте очевидное

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

Когда мы отказались от скобок, возникло две проблемы:

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

    =: listSum(list: $list)
    list: listCreate(item: 1; item: 2; item: 3)

  • К вызову строки нужна ответка — сделали именование строки name:. Почему двоеточие? Потому что мы в обыкновенном письме через двоеточие разворачиваем мысль. Чем больше похоже на нормальную жизнь, тем лучше.

«Ага, а с какой строки код начнет исполнятся, умник?» Спросил у меня разраб.

«Ок, будет обозначена стартовая строка =:», вздохнул я...

  • Если скобки только у функций, как быть с математическими операциями (A + B) * 10? И вот на это сразу ответа не нашлось, поэтому волевым решением решили, что с математикой разберемся позже. По умолчанию все как калькулятор типа работает и на худой конец можно через отдельную строку посчитать:

    =: $sum * 10
    sum: #field_a + #field_b

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

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

Функции, заточенные под задачу

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

Не увлекайтесь сокращением

В начале мы начали с простых функций, которые будет осуществлять преобразования, складывать списки и тому подобное. И сразу захотелось как-то так listSum($list), но это понятно, если у функции один параметр на вход и он понятен из контекста функции.

А если dateAdd(#date; 10; ; ; ; ; "Y-m-d H:i"; ). Что? Понятное дело, если вы работаете в IDE — она вам подсказывает, какой параметр по счету что означает. А если где-то интегрированное — то не всегда. Сюда пригодились отмененные из концов строк точки с запятой. Могли бы сделать запятые? Могли, но точка с запятой нам показалась более читаемой. Правда если не подписывать параметры, то лучше, наверное, запятую.

Но мы решили подписывать параметры. Вот так: dateAdd(date: ; days: ; hours: ; minutes: ; months: ; years: ; format: "Y-m-d H:i"; lang: ) — больше текста, но понятнее тому, кто первый раз видит. Надо только сделать автозаполнение, чтоб руками не пришлось набирать.

Также такой подход позволяет не указывать часть параметров и ставить их в произвольном порядке (что ухудшает читаемость и мы просим так не делать) — интерпретатору и человеку понятно, какие пропущены: dateAdd(date: #date; days: 10; format: "Y-m-d").

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

Хотя бы в начале, не нарушайте собственные принципы в базовых вещах

Несмотря на то, что хочется пропустить как listSum($list) так и listSum(list: $list), я противник такой истории. Исключения неизбежно будут и даже больше, чем вам хочется. Надо постараться не далать их на самом базовом уровне.

Вовремя остановитесь

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

Сокращайте возможности в пользу упрощения

В нашем случае, анализ потенциального решения показал, что нам не нужно все разнообразие SQL. Поэтому мы отказались от SQL и упаковали запросы к БД в наши же функции:

=: select(table: 'table_name'; field: 'field_name'; where: 'field_name_id' = #anchor)

И здесь мы сознательно ввели ограничения:

  • where сравнивает по пересечениям и не обращает внимание на тип (те 3 = 3 и 3 = "3" и 3 = [1,2,3] и 3 = ["1","2","3"]);

  • Пустота и пустое значение равны для поиска "" = nil;

  • Запретили сравнение больше/меньше со списками;

  • И самое страшное отменили OR, оставили только AND через множественный параметр ...; where: 'f_1' > 10; where: 'f_2' = #sum. Почему отменили OR? Потому что его можно было эмулировать архитектурой решения, и практика применения показала невысокую частоту применения. Поэтому решили, что упрощение в приоритете (непростое было решение, и в PRO версии мы его добавим).

Добавляйте автозаполнение везде, где получится

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

Не забывайте про хоткеи

Одно дело добавить параметр, другое дело удалить. Заполнил по умолчанию, а там лишние параметры для конкретного случая попали. Сначала не поняли как с этим быть. А потом пришла идея: выделять параметр хоткеем и потом по бэкспейсу его удалять. В зависимости от того, где стоит курсор относительно ;, выделяется параметр вперед или назад.

Вроде бы ничего фантастического, но скорость работы с кодом выросла в 10 раз.

Добавляйте сахар только для тех мест, от бойлерпринта в которых вы сами устали

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

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

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

// json`[1,2,3]`

=: select(table: $#ntn; field: 'id'; where: 'type' = json`[1,2,3]`)

После того как это оказалось удобно, мы решили попробовать засунуть внутрь таких-же кавычек и математику:

=: select(table: $#ntn; field: 'id'; where: 'sum' = math`(#field_a + #field_b)/10`)

И уже это решение пошло в рабочую версию.

Комбинации лучше, чем отдельные экзотические символы

В примере выше можно увидеть вот такой элемент —$#ntn. Есть и другие с $#. Дело в том, что тяжко было каждый раз набирать таблицу, и мы пытались приспособить что-то, что возвращало бы какие-то системные константы и переменные. Сначала мы для этого сделали функции без параметров. nowTableName() например возвращало имя текущей таблицы. И именно их на первом этапе мы решили вызывать через быстрые переменные. И тут стало понятно, что из понятных символов есть еще @ % и &.

Проценты были отброшены как слабочитаемые, а амперсанд из-за того, что он на другой стороне клавиатуры. Мне хотелось, что бы тыки в клавиши были рядом. И дальше волей случая @ уехал в другой сахар, а для остальных мы решили использовать комбинации # и $ так как их быстро и привычно набирать. Причем в логике приложения получались разные результаты их комбинаций:

  • $# — системные переменные

  • #$ — определить имя поля через другую строку

  • $$ — определить имя строки через другую строку

  • @ — аналог функции select

И уже сильно потом досыпались:

  • @$ — глобальная внетранзакционная переменная

  • $@ — переменная передаваемая в рамках одного процесса

Вот по этим последним я всегда путаюсь кто из них кто, так-как они сформированы не на основе логики, а просто из находящихся рядом клавиш.

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

Постарайтесь избегать диких цветов в подсветке

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

Здесь я не знаю — напишите что-нибудь в комментариях, что вы думаете про подсветку, насколько критично делать настройку подсветки для пользователя?

Не пытайтесь казаться крутыми

Признаюсь. Был грешок. Очень хотелось, как в больших языках, добавить что-то крутое. И мы добавили — рекурсии. С теми самыми фигурными скобками :)

=: $split{var: "fruits" = $code2}

 split: if(condition: $#fruits != $#lc; then: $str1; else: "")
    str1: strAdd(str: $#fruits[0]; str: ", "; str: $split{var: "fruits" = $fruitsCut})
        fruitsCut: listCut(list: $#fruits; cut: "first"; num: 1)

code2: listCreate(item: "apple"; item: "banana"; item: "lemon")

// Результат: "apple, banana, lemon, "
// Данный пример приведен здесь как пример, эта конкретная операция выполняется функцией listJoin.

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

Подмечайте, где у вас не стыкуется или не удобно

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

=: linkToInput(title: "Some title"; code: $save_action; button: "Сохранить")

```save_action:totum
=: insert(table: 'some_table'; field: 'some_field' = $#value)
```

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

Конкретно в этом месте ведущий разраб говорил, что «это невозможно никогда» из-за особенностей предварительной обработки этих кодов интерпретатором.

Но я 4 года не терял надежды, что может быть ситуация разрешится. И это случилось.

Однако, в таких случаях не стоит доставать разрабов тем, что они это никак не сделают. В моем случае, я подходил с этим вопросом не чаще 1 раза в год.

Заключение

Вот как-то так получилось.

Что люди делают можно посмотреть в этой ветке форума на GitHub.

Если вы тоже разрабатывали DSL — поделитесь в комментах своими находками.

Комментарии (32)


  1. rsashka
    09.09.2022 15:43
    +2

    А мне казалось, что это я заморочился в NewLang с разными комбинациями спецсимволов:

    $# — системные переменные, #$ — определить имя поля через другую строку, $$ — определить имя строки через другую строку, @ — аналог функции select

    И уже сильно потом досыпались: @$ и $@


    1. Hrodvitnir
      09.09.2022 18:04
      +3

      Очень зубодробительные штуки вышли, конечно
      Особенно то, что #$ и $# это абсолютно разные и не связанные по смыслу вещи.

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


      1. AlexeyPolunin Автор
        09.09.2022 18:11

        На практике в 99% случаев нужно только $#. А пара была выбрана просто потому, что ее очень быстро набирать безо всякого автозаполнения. По практике — это оказалось очень удачным решением.

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


  1. rsashka
    09.09.2022 15:47
    +5

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

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

    Хотя в паре комментариев сложно все написать ...


    1. AlexeyPolunin Автор
      09.09.2022 17:40

      Это стандарт, когда пишешь: «знаете, я тут синтаксис придумал» — миллион людей спросят «а зафига?» :) В моем случае это решало простую задачу — научить пользователя, который вообще никакого языка не знает дистанционно за 2 дня. Это получается. А так, если есть возможность отказаться от разработки DSL — надо отказаться.


  1. iliazeus
    09.09.2022 16:37
    +2

    Очень круто, что вам удобно решать ваши задачи на вашем языке. В конце-концов, в DSL, как мне кажется, главное — DS. Но с точки зрения мимопроходила, выглядит немного... непривычно? некрасиво? Не знаю, как сказать одним словом, поэтому попытаюсь описать по пунктам в треде.


    1. iliazeus
      09.09.2022 16:38
      +2

      Всегда думайте о том, как вы будете потом обучать других людей

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


    1. iliazeus
      09.09.2022 16:39
      +3

      Удаляйте лишнее

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


      1. AlexeyPolunin Автор
        09.09.2022 17:36
        +1

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

        Вообще если стремится сделать очень похоже, но не совсем в концепции приложения — лучше взять JS или Lua.


        1. GospodinKolhoznik
          09.09.2022 21:47
          +3

          Вы не первый, кто попытался сделать ЯП, на котором бы могли программировать люди не умеющие программировать. Ещё в 50е пытались сделать это. Самые знаменитые языки, на которых, как предполагалось, сможет писать любая секретарша это Cobol и SQL. Однако пока никому не удалось сделать такой язык.

          Но вы в любом случае молодец!


          1. AlexeyPolunin Автор
            10.09.2022 00:05
            +2

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

            Сейчас самая большая проблема для нас — это не объяснять синтаксис (с этим все совсем просто), а с объяснением хорошей архитектуры решения. В 60% случаев начинают делать так, как у них было в табличке эксель и соответсвенно тянут оттуда все архитектурные ограничения. Вот это быстро пофиксить не получается — делаем консультации, записываем видосы. Если пользователь не программировал никогда и ничего и разбирается со всем сам, то сейчас он со своего второго проекта начинает понимать как таблички должны быть организованы, а я хочу чтоб с первого.

            Но если проект простой — до 5 табличек, то там любая архитектура прокатывает. А потом (после этих 5 первых) таблички людям мозг захватывают и их система начинает расти 5 -> 30 -> 100 -> 150 (это реально уже проект-монстр который даж меня пугает).


            1. pfffffffffffff
              10.09.2022 09:10

              Пользователи не хотят кодить, это тоже нужно понимать, даёшб им конструктор кода


              1. AlexeyPolunin Автор
                10.09.2022 12:12
                +1

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

                Но идея эта распространена и вроде как есть куча конструкторов. Я BPMS например к конструкторам отношу. А мы специально хотели, чтоб был код. Должен же быть в мире выбор :)


    1. iliazeus
      09.09.2022 16:44
      +3

      Добавляйте автозаполнение везде, где получится

      Не забывайте про хоткеи

      Постарайтесь избегать диких цветов в подсветке

      Судя по этим пунктам, мне кажется, что вам не хватило в начале еще одного, возможно, более главного:

      Изучите существующие инструменты для написания DSL

      Подсветку синтаксиса можно сделать без указания конкретных цветов, а с указанием семантики токенов. Самое простое — грамматики TextMate, которые поддерживают из коробки, например, VS Code и Shiki.

      А все эти три пункта можно решить, если постараться поддержать хотя бы некоторые фичи из Language Server Protocol. При этом у вас почти сразу появится много мощных инструментов для вашего DSL.


      1. AlexeyPolunin Автор
        09.09.2022 17:34
        -1

        Мне хотелось, что бы небыло отдельного специального IDE типа VS Code — те все должно было быть из коробки.


    1. iliazeus
      09.09.2022 16:49
      +5

      Комбинации лучше, чем отдельные экзотические символы

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

      Не совсем понимаю, например, почему =: вам кажется лучше, чем что-то вроде start: или main:.

      Или почему, к примеру, $#smth — это системные переменные, а не, например, $sys.smth?


      1. AlexeyPolunin Автор
        09.09.2022 17:33

        $sys.smth есть точка и мне хотелось, что бы стартовый символ или пара отличались. Мы используем точку в паре мест, но в основной массе старались ее избегать. Когда 3-й день программируешь — точки плохо читаются.


      1. AlexeyPolunin Автор
        09.09.2022 17:44

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

        a1=:

        a2=:

        ch1=:


  1. ris58h
    09.09.2022 17:18
    +1

    Нравится идея с определением переменных после. Где-то в другом языке подсмотрели?


    1. AlexeyPolunin Автор
      09.09.2022 17:31

      Нет, не подсматривал


    1. iliazeus
      09.09.2022 18:19
      +2

      Из других языков есть, например, Haskell и подобные:

      foo = 123 + bar
        where
          bar = 456


      1. AlexeyPolunin Автор
        09.09.2022 18:59

        Во, мне нравится как Haskell думает :)


  1. beeptec
    09.09.2022 18:42

    А чем для не программистов плох Ms Access, там на визардах практически всё можно автоматизировать, там же и встроенный SQL builder куча других плюшек которые можно вполне себе применять?

    Я лет 20 тому, на нем многопользовательские армы делал и кадастры, ГИС и т.п. для него даже компилятор есть в exe формат.


    1. AlexeyPolunin Автор
      09.09.2022 19:01

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


  1. GospodinKolhoznik
    09.09.2022 21:30
    +1

    #field_name и получаем вместо него значение этого поля

    Если значение поля field_name_A равно field_name_B, а значение поля field_name_B равно 777, то правильно ли я понимаю, что ##field_name_A = 777 или нет?


    1. AlexeyPolunin Автор
      09.09.2022 23:57

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

      = : #$field_name
      
      field_name: #h_field_name_a


  1. Wyrd
    10.09.2022 00:14
    +1

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


    1. AlexeyPolunin Автор
      10.09.2022 00:27

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

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


      1. Wyrd
        10.09.2022 00:43
        +1

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

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


        1. AlexeyPolunin Автор
          10.09.2022 12:14

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


  1. gochaorg
    10.09.2022 02:35
    +3

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

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

    например Java и C# общие:

    вызовы через круглые скобки, аргументы - разделены запятыми, присваивание слева (переменная) на право (значение) через символ равно, передача значения - вызов функции - поддается той же логике: result = fun ( arg1, arg2 ) - тоже все значения текут справа на лево: сначала аргументы в функцию, из функции в результат

    это уже стало на столько естественно, что как-то меньше попадается вот этого

    result := fun ( arg1, arg2 )

    или

    procedure( arg1, arg2, result ) - тут результат засовывается в конец и вообще не понятно становиться как построить цепочку выражений, вообще в том же bash, powershell для этого сделали вертикальную черту

    тенденция использовать спец символы в именах переменных в mainstream уходит, медленно уходит PHP (да простят), там например переменные начинаются с $, а с perl там еще вроде хлеще было

    языки постепенно по синтаксису упрощаются и идут в сторону лаконичности, в том же C++ и PHP вызов метода через -> (obj->method(arg,arg)) (через точку то же есть, но у них семантика разная), а уже в Java и в других поздних уже точка (obj.method(arg,arg))

    убираются опциональные детали, а у вас на оборот, начинаются проблемы $ $@ @$ ' " ` ``` с таким успехом не долго дойти до bash / perl - а это уже тупик будет

    я бы посмотрел на более лаконичные решения, например очень сложно из нормального языка выкинуть круглые скобки - они задают порядок вычисления, а если серьезно говорить - то структуру (AST), все остальное просто, от других вещей можно избавиться, например в Scala есть массивы, но их использование не отличается особо от функций array(item) в Scala, то же что array[item] в Java, просто по смыслу, работа с функций (fn(a)) не сильно отличается от работы с массивом (arr(a)) (при условии что функция чистая) - вот в Scala и выкинули лишнее

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

    Когда дойдете до определения тела функций - последовательности вычислений, то лучше сразу откинуть идею со statements и перейти к expressions, и за одно циклы while выкинуть оставить только recursion и tail recursion, я бы еще if выкинул, заменил бы на pattern-match


    1. AlexeyPolunin Автор
      10.09.2022 12:41
      +1

      Спасибо, что написали — у меня была возможность еще немного поразмышлять в этом направлении. Если говорить про язык, то вы все верно пишете (не просто так же языки эволюционировали).

      Дело в том, что у нас не язык — к нему надо относится как к «конфигу на стероидах».

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

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

      А я же сознательно делал «инстаграм синтаксис», так-как мой пользователь — это человек, который про программирование не знает. А вот # как тег и @ как указание пользователя ему знакомы. Вот какой паттерн мы активировали.

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

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

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