image

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


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


Основные свойства языка:
  • Возможность работы как в режиме интерпретатора, так и компилятора*.
  • Динамическая и статическая типизация с возможностью указания типов в явном виде.
  • Статическая типизация является условно строгой (автоматическое приведение типов отсутствует, но допускается преобразование между некоторыми типами данных, например, целое число может быть автоматически преобразовано в вещественное или рациональное, но не наоборот).
  • Автоматическое управление памятью.
  • ООП в виде явного наследования классов и «утиная» типизация.
  • На уровне синтаксиса поддержка нескольких типов функций (обычные и чистые функции без побочных эффектов).
  • Необязательные и именованные параметры функций.
  • Простая интеграция с уже существующими программными библиотеками (в том числе импорт нативных переменных и функций из С/С++).
  • Имеется REPL read-eval-print loop — «цикл: чтение — вычисление — вывод».

Зачем нужен NewLang?


У всех современных языков программирования происходит постоянное развитие (усложнение) синтаксиса по мере выхода новых версий. Это является своего рода платой за появление новых возможностей и воспринимается пользователями как естественное явление.


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


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


Основной синтаксис — для написания программ в объектно-ориентированном (императивном) и декларативном стилях, который основан не на зарезервированных ключевых словах, а на системе строгих грамматических правил. Имеется возможность расширения основного синтаксиса за счет использования макросов. Расширенный синтаксис — программные вставки на языке реализации (С/С++), когда основного синтаксиса становится недостаточно.


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


У NewLang тензорные вычисления и рациональные числа неограниченной точности доступны «из коробки». Они поддерживаются на уровне синтаксиса для записи литералов соответствующих типов, а простые арифметические типы данных являются скалярами (тензорами нулевой размерности). Реализация тензорных вычислений сделана на базе библиотеки libtorch, а рациональные числа с использованием OpenSSL.


Новые глобальные фичи и изменения в синтаксисе:


Простые чистые функции удалены


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


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


Зафиксирован синтаксис операторов проверки условия и циклов.


Изменен и упрощен синтаксис операторов проверки условия (импликации) и цикла, для которых оставлено только по одному варианту. Проверка условия записывается в виде оператора математического следования -->, а цикл с помощью оператора <->.


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


\if(...){
    ...
} \elif(...) {
   ...
} \else {
   ...
};

или


 \while( ... ){ 
     ...
}; 

Конструкция else у операторов цикла


Теперь оператор цикла while поддерживает конструкцию else, которая выполняется если условие входа в цикл не было выполнено. Это поведение отличается от аналогичных конструкций в языке Python, у которого секция else выполняется всегда, кроме прерывания цикла по break.


Ветка else у оператора цикла записывается так же как и ветка иначе в условном операторе, т. е.


[ cond ] <-> {
   ...
}, [_] --> {
   ...
};

Или тоже самое, но с использованием макросов:


\while(cond) {
   ...
} \else {
   ...
};

Пространства имен


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


ns {
    name {
        var := 0; # Имя переменной будет ns::name::var
        ::var := 1; # Переменная из глобального пространства имен
    }
}

Программные модули


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


Имя модуля начинается на префикс @, а структура каталогов указывается через точку. Причем концепции программных модулей и пространства имен объединены, и полное имя переменой из предыдущего абзаца будет @root.dir.module::ns::name::var, где root и dir это каталоги в файловой системе, а module — имя файла.


Объектно ориентированное программирование


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


:NewClass := :Class() { #  Новый тип (класс)
    field := 1;
    method() := {};
};
obj := :NewClass(); # Экземпляр класса

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


:NewClass2 := :NewClass() { # Новый класс на базе существующего
    field ::= 2; # Будет ошибка, т. к. поле field уже есть в базовом классе
    method() = {}; # Аналог override, т.к. method должен существовать в базовом классе
};

Прерывания, возврат и обработка ошибок


Изменена, а точнее полностью переделана идеология возвратов из функций и обработки ошибок. Теперь она чем-то похожа на подход, примененный в Ruby. Любая последовательность команд заключенные в фигурные скобки (в том числе тело функции), рассматривается как блок кода у которого нет специального оператора аналога return, который возвращает какое либо значение. Просто любой блок кода всегда возвращает последнее вычисленное значение (это чем то похоже на оператор «запятая» в языках C/C++).


Для того, чтобы прервать выполнение кода используются две разные команды — прерывания, которые условно можно назвать положительным и отрицательным результатом. Что примерно соответствует семантике их записи. "Отрицательное" прерывание записывается в виде двух минусов, а "положительное" прерывание в виде двух плюсов, т.е. -- или ++.


По умолчанию данные операции возвращают пустое значение. Чтобы прерывание вернуло результат, возвращаемые данные нужно записывать между парой соответствующих символов, т.е. -- 100 --, что является близким аналогом оператора return 100; в других языках программирования, а ++«Строка»++ — аналогом return «Строка»;.


Хотя более точным аналогом этих операторов будет все таки не return, а throw, т.к. эти команды не только прерывают выполнение последовательности команд в блоке, но их еще можно «ловить». Для этого используется блок кода с соответствующей семантикой, {++} — блок кода, который перехватывает положительные прерывания и {--} — блок кода, который перехватывает прерывания, созданные операторами --.


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


Например, возврат из нескольких вложенных функций без необходимости обрабатывать результат возврата каждой из них. В этом примере функция Test перехватывает "положительные" прерывания из вложенных функций:


    Test0(arg) := { \if($arg==0) \return("DONE - 0"); «FAIL» };
    Test1(arg) := { \if($arg==1) \return("DONE - 1"); Test0($arg); };
    Test(arg) := {+ \if($arg >= 0) Test1($arg); $arg; +};

    Test(0); # Вернет «DONE — 0» возврат из вложенной функции Test0
    Test(1); # Вернет «DONE — 1» возврат из вложенной функции Test1
    Test(2); # Вернет «FAIL» возврат из вложенной функции Test0
    Test(-2); # Вернет -2 — возврат из функции Test

Есть еще блок {* … *}, который перехватывает оба типа прерываний. Такой блок кода поддерживает типизацию возвращаемого значения, что позволяет в явном виде указывать типы данных, которые нужно перехватывать. Например, {* ... *} :Type1 — будет перехвачено прерывание вида ++ :Type1 ++ или --:Type1--, что позволяет очень гибко формировать логику работы программы.


Блоки кода с перехватом исключений также поддерживают оператор иначе (\else) который, по аналогии с оператором \else в циклах, выполняется только тогда, если прерывания не произошло.


Можно указать сразу несколько типов, которые нужно перехватывать:


    {* 
        ....
    *} <:Type1, :Type2, :Type3>;

Бинарная сборка под Windws:


В текущем релизе версия clang повышена 15, а вызовы нативных функций опять реализованы с помощью libffi, что в итоге позволило собрать бинарную сборку не только под Linux, но и под Windows. И теперь чтобы поиграться с REPL read-eval-print loop можно скачать уже готовый бинарник.


Подробная информация о языке:



Обратная связь


Если у вас появятся предложения по развитию нового или улучшению уже существующего функционала NewLang, пишите.


Примеры кода


#!../output/nlc --eval
# Определение функции hello
hello(str) := { 
    # Импорт стандартной C функции
    printf := :Pointer('printf(format:FmtChar, ...):Int32');
    # Вызов C функции с проверкой типов аргументов по строке формата
    printf('%s', $str);  
    # Возврат значения из функции hello
     $str;
};

hello('Привет, мир!'); # Вызвать функцию</code>

Вывод (первая строка выводится с помощью printf, а вторая — возвращаемое значение функции hello):


    Привет, мир!
    Привет, мир!

Пример скрипта для вычисления факториала 1000


#!../output/nlc --eval

fact := 1\1;  # Рациональное число без ограничения точности
mult := 1000..1..-1?; # Сделать из диапазона итератор для множителей от 1000 до 2
[mult ?!] <-> {      # Цикл, пока не закончатся данные итератора
    # Получить текущий множитель и перейти на следующий элемент итератора
    fact *= mult !; 
};
fact # Вывести итоговый результат

Вывод:


Много цифр

402387260077093773543702433923003985719374864210714632543799910429938512398629
020592044208486969404800479988610197196058631666872994808558901323829669944590
997424504087073759918823627727188732519779505950995276120874975462497043601418
278094646496291056393887437886487337119181045825783647849977012476632889835955
735432513185323958463075557409114262417474349347553428646576611667797396668820
291207379143853719588249808126867838374559731746136085379534524221586593201928
090878297308431392844403281231558611036976801357304216168747609675871348312025
478589320767169132448426236131412508780208000261683151027341827977704784635868
170164365024153691398281264810213092761244896359928705114964975419909342221566
832572080821333186116811553615836546984046708975602900950537616475847728421889
679646244945160765353408198901385442487984959953319101723355556602139450399736
280750137837615307127761926849034352625200015888535147331611702103968175921510
907788019393178114194545257223865541461062892187960223838971476088506276862967
146674697562911234082439208160153780889893964518263243671616762179168909779911
903754031274622289988005195444414282012187361745992642956581746628302955570299
024324153181617210465832036786906117260158783520751516284225540265170483304226
143974286933061690897968482590125458327168226458066526769958652682272807075781
391858178889652208164348344825993266043367660176999612831860788386150279465955
131156552036093988180612138558600301435694527224206344631797460594682573103790
084024432438465657245014402821885252470935190620929023136493273497565513958720
559654228749774011413346962715422845862377387538230483865688976461927383814900
140767310446640259899490222221765904339901886018566526485061799702356193897017
860040811889729918311021171229845901641921068884387121855646124960798722908519
296819372388642614839657382291123125024186649353143970137428531926649875337218
940694281434118520158014123344828015051399694290153483077644569099073152433278
288269864602789864321139083506217095002597389863554277196742822248757586765752
344220207573630569498825087968928162753848863396909959826280956121450994871701
244516461260379029309120889086942028510640182154399457156805941872748998094254
742173582401063677404595741785160829230135358081840096996372524230560855903700
624271243416909004153690105933983835777939410970027753472000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000\1


Как посмотреть?


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


  1. yurec_bond
    07.11.2022 17:00
    +12

    OMG. /Слеши /перед /ключевыми /словами /в /разы /понижают /читаемость /языка.


    1. rsashka Автор
      07.11.2022 17:13

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

      А так как слеш перед словом, это макрос определенный пользователем, то и сами слова могут быть о-го-го какими :-)


      1. Tangeman
        08.11.2022 12:28

        Хоть по бэкслэшам уже не раз прошлись чуть ранее, есть гораздо менее приятный момент для тех у кого немецкая раскладка, где бэкслэш - это необходимость нажимать две клавиши одновременно (причём вторая клавиша это не shift а правый alt, он же alt gr). А нужен он довольно часто, судя по всему.


        1. rsashka Автор
          08.11.2022 12:56

          Нет ничего совершенного :(

          Я на русской раскладке тоже мучаюсь, но не беклешем, а с решеткой "#"


  1. dynamicult
    07.11.2022 17:27
    +4

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

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


    1. rsashka Автор
      07.11.2022 17:31

      Причина проста - в языке слишком много соли.

      А что это, можно какой нибудь пример? И можете привести пример языка, в которых "соли" мало?


      1. dynamicult
        07.11.2022 17:37
        +2

        На хабре когда-то был хороший перевод статьи про соль и чем она вредна https://habr.com/ru/post/348282/

        можете привести пример языка, в которых "соли" мало

        JavaScript


        1. rsashka Автор
          07.11.2022 17:55

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

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


          1. tolik_anabolik
            08.11.2022 05:41
            +2

            Думаю, dynamicult имел ввиду мусор в синтаксисе языка – все эти $ :: \ := и т.п. В этом я с ним соглашусь.

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

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


            1. rsashka Автор
              08.11.2022 06:09
              -1

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


              1. iCpu
                08.11.2022 07:08
                +1

                Есть небольшая разница, нужно ли мне писать этот символ иногда, чтобы подчеркнуть какую-нибудь особенность типа double ** matrix_p или специальную операцию Singleton::instance()->foo() - или ::мне \нужно писать $их \чуть-\ли не в \каждом :слове.

                Вы, конечно, можете возразить, что тут перемешаны переменные, макросы, типы и области видимости. Но мне не просто всё равно, мне абсолютно всё равно. Зато кому не всё равно, так это авторам более зрелых языков, которые у себя засахарили всякие auto, using и прочие &, чтобы исходник из адского ада

                for (std::vector<MahType<Foo, Bar::Buz<BufferType, std::allocator<BufferType>>*>::iterator i = foos.begin(); i != foos.end(); ++i) { 
                    (*i)->foobar(); 
                    /*...*/
                }

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

                using BarBuzBuffer = Bar::Buz<BufferType, std::allocator<BufferType>>;
                using MahFooType = MahType<Foo, BarBuzBuffer>;
                std::vector <MahFooType*> foos;
                /*...*/
                for (auto _i = foos.begin(); _i != foos.end(); ++_i) { 
                    MahFooType * i = (*_i); 
                    i->foobar(); 
                    /*...*/
                }

                или менее совместимый

                for (auto * i : foos) {}


                1. rsashka Автор
                  08.11.2022 07:36

                  Вообще то в приведенных вами примерах, косая черта перед термином обязательно будет всего в одном месте, перед for, точнее \while(){ }

                  Если говорить про префиксы вообще, то он должен быть при объявлении $foos и $i, как локальных переменных.

                  Конечно, при желании можно через макросы определить \BarBuzBuffer и \MahFooType в конструкции using, но лучше это сделать с помощью создания новых типов.

                  Что же касается аналога цикла foreach в NewLang, то его можно сделать двумя способами, оператором раскрытия списка:

                      $summa := 0;
                      $dict := (1,2,3,4,5,);
                      \while( dict ) {
                          # Первый элемент словаря перемещается в item
                          $item, dict := ... dict; 
                          summa += item;
                      };

                  Или с помощью итератора:

                  $fact := 1\1;
                  $mult := 1000..1..-1?; # Итератор от 1000 до 2
                  
                  \while( mult ?! ) {
                      fact *= mult !; 
                  };
                  fact; # Вывести итоговый результат

                  Причем, если вас смутили знаки вопроса, то можно сделать и так:

                  $mult2 := \iter(1000..1..-1);
                  \while( \curr(mult2) ) {
                      fact *= \next(mult2); 
                  };
                  


                  1. iCpu
                    08.11.2022 09:30

                    Меня смущает, что в вашем "примере покороче без знаков вопроса" пять слешей. Которые не нужны.

                    Кстати, а могут быть одноимённые функции, макросы и переменные?
                    $next := \next(next(foobar))
                    А может ли макрос возвращать макрос, который можно разыменовать слешем?
                    \\findMacroFor(situation)


                    1. rsashka Автор
                      08.11.2022 09:41

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

                      Функция с именем макроса тоже может быть как и такой же объект в другом модуле или пространстве имен.

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


                      1. iCpu
                        08.11.2022 09:47
                        +2

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

                        Помню я те прекрасные времена, когда ошибка в программе на питоне была из-за двух пробелов. Теперь ещё и слеши...

                        Макросы не возвращаются и не разименовываются, так как обрабатываются отдельным парсером ДО анализа компилятором языка.Именно этот момент позволяет использовать в макросах не только топовые операторы, но и полностью менять сам синтаксис (при большом извращенном желании).

                        То есть параметризировать сборку через параметризацию подстановки макросов нельзя? Как-то странно.


                      1. rsashka Автор
                        08.11.2022 09:54

                        Помню я те прекрасные времена, когда ошибка в программе на питоне была из-за двух пробелов. Теперь ещё и слеши...

                        Слеши хотя бы видать, в отличии от пробелов :-)

                        То есть параметризировать сборку через параметризацию подстановки макросов нельзя?

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


                      1. iCpu
                        08.11.2022 11:36
                        +1

                        Слеши хотя бы видать, в отличии от пробелов :-)

                        PVS-Studioне даст соврать, видимость символа ни капельки не уменьшает вероятность опечатки или пропуска правки во время копипасты.

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

                        Вопрос с подвохом, потому что оба варианта хуже. Если позволить многоуровневые макросы вида \\\foo() -> \\bar() -> \buz()получается нечитаемая фигня без контроля вложенности, ломающая всё на своём пути. Если не позволить, параметризация макросов должна проходить через ветвления аля #ifdef #elif #endif. Что, в общем-то, неплохо, но ничем не лучше уже существующих решений, как по читаемости, так и по удобству. Вам бы макросы сделать, как код, выполняющийся над синтаксическим деревом языка в месте подстановки. Но в этом месте можно и порваться.


                      1. rsashka Автор
                        08.11.2022 12:03

                        Из-за особенностей синтаксиса NewLang, его компилятор (читай парсер) получается очень простой, так как для анализа ему не требуется AST со списком определенных ранее идентификаторов и типов данных.

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

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

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

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

                        Цитата из статьи:

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

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

                        Например, в NewLang лямбда функция не имеет специального синтаксиса, а при создании проверяется имя создаваемой функции, и если оно отсутствует (вместо имени используется подчерк), что объект не регистрируется (точнее регистрируется, но без имени).

                        Поэтому идея в статье не только здравая, но и вполне рабочая, сам проверял :-)


                      1. iCpu
                        08.11.2022 13:33
                        +2

                        Не, идею с подменой макросов лучше оставить за бортом. На плюсах уже сколько десятилетий блюют от заголовочника <windows.h> и его глобально переопределения макросов min и max, перекрывающее даже стандартную библиотеку std. Вы НЕ хотите такого в своём ньюланге. Как минимум, импорт-экспорт нужно реализовывать, как в питоне, контролируя пространство. в которое попадают импортированные символы.

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


                      1. rsashka Автор
                        08.11.2022 13:49

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

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


                      1. rsashka Автор
                        08.11.2022 15:49

                        А если делать импорт только в конкретную область имен, то что мешает область имен использовать и в макросах? Это нужно обмозговать. Еще раз спасибо!


                1. k0stu
                  08.11.2022 11:54

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

                  Вы серьезно называете это читаемым?


                  1. iCpu
                    08.11.2022 13:04
                    +1

                    "Куда более читаемым" - да. Я плюсы в пример привожу не столько потому, что на них пишу, сколько потому, что на них можно писать:
                    1) нечитаемо
                    2) ужасно
                    3) страшно
                    4) не по принятым стандартам


  1. Autochthon
    07.11.2022 17:45
    +2

    А что собственно в нем нового?



  1. ShefEr
    07.11.2022 18:52
    +7

    Интересует какую проблему решает этот язык, которую не смогли решить уже существующие


    1. perfect_genius
      08.11.2022 01:13
      +1

      У NewLang тензорные вычисления и рациональные числа неограниченной точности доступны «из коробки».

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


  1. s_f1
    07.11.2022 19:18
    +3

    Ну наконец-то новый язык! А то всё старые. Мы заждались!
    PS серьёзно – что за название? Это как автомобиль NewCar, или отель NewHotel.


    1. rsashka Автор
      07.11.2022 20:04
      -2

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


    1. dyadyaSerezha
      07.11.2022 23:44
      +8

      Да, неудачное название. Предлагаю такое, покруче:

      /::New<->/:Lang:


      1. rsashka Автор
        08.11.2022 06:04

        Тогда уж HabrLang, так как он делается в том числе и с вашей помощью (Хабр — ума палата)


  1. BugM
    07.11.2022 21:18
    +2

    А зачем он? В 21 веке принято языки делать для какой-то цели. Go - простой для перекладывания джейсонов. Rust - более безопасная замена плюсам. Kotlin - джава с кучей сахара. И тому подобное.

    А ваш язык зачем нужен?


    1. rsashka Автор
      07.11.2022 21:22
      -2

      Вы не заметили самую первую главу с названием "Зачем нужен NewLang?" или что-то в ней не поняли?


      1. BugM
        07.11.2022 21:28
        +2

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

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


        1. rsashka Автор
          07.11.2022 21:39

          Дальше я пишу про новые фичи текущего релиза.

          А ниже есть ссылки на полную документацию, в том числе и с примерами, преобразования типов и data comprehensions


          1. BugM
            07.11.2022 21:50
            +4

            Простите, но нет. Это однострочники которые непонятно зачем.

            Примеры и сравнение с другими языками должны быть комплексными. Чтобы по ним можно было понять какая задача решена и оценить почему она на вашем языке решается лучше или удобнее.


            1. rsashka Автор
              07.11.2022 22:08
              +1

              Примеры и сравнение с другими языками должны быть комплексными. Чтобы по ним можно было понять какая задача решена и оценить почему она на вашем языке решается лучше или удобнее.

              А вот тут я с вами полностью согласен! Это обязательно нужно будет делать! Надеюсь, что в следующей версии я доделаю ООП (сейчас нет конструкторов и деструкторов) и получится сделать импорт нативных классов C++.

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


  1. newpy
    07.11.2022 21:20
    +2

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


    1. rsashka Автор
      07.11.2022 21:33

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


      1. Ritan
        07.11.2022 22:08
        +2

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

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


        1. rsashka Автор
          07.11.2022 22:17
          -2

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

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

          Получил код, преобразовал в свой набор ключевых слов, отправил его на ревью, например китайцу, а он его преобразовал в свой вариант DSL для проверки, а потом вернул назад. Как вам такая фишка? Это даже круче чем в 1С :-)


          1. Ritan
            08.11.2022 00:21
            +2

            Увы. Подозреваю это хорошо звучит только в теории. Это будет ад для поддержки любых средств ревью кода( gitlab, github итд ). Плюс такая система будет наверняка приводить к грязным дифам в любой VCS. Файлы проектов unity в виде автогенерированных xml не дадут соврать


            1. rsashka Автор
              08.11.2022 06:02

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


      1. NN1
        08.11.2022 00:46

        Может стоит посмотреть на примеры других тактх языков?

        Например: https://github.com/rsdn/nitra


        1. rsashka Автор
          08.11.2022 05:57

          Посмотрел ваш пример языка:

          using Nemerle.Extensions;
          
          class EventRaiser
          {
              public event Ev : Action;
          }
          
          class Cls
          {
              public Raiser : EventRaiser = EventRaiser() <-{
                  Ev += () => Handler()
              }
              
              Handler() : void
              {
              }
          }
          

          Или другой пример из репозитория:

          Hidden text
          using Nitra;
          using Nitra.Runtime;
          using Nemerle;
          using Nemerle.Collections;
          using System.Collections.Generic;
          
          language SimpleCalc
          {
            syntax module SimpleCalcSyntax start rule Start;
          }
          
          syntax module SimpleCalcSyntax
          {
            using Nitra.Core;
          
            [StartRule]
            syntax Start = Expr !Any { [Cached] Value() : double = Expr.Value(); }
          
            regex Digits = ['0'..'9']+;
            regex Id     = ['a' .. 'z', 'A' .. 'Z']+;
          
            [StartRule]
            syntax Expr
            {
              Value() : double;
              missing Value = double.NaN;
          
              | [SpanClass(Number)]
                Num        = Digits              { override Value = double.Parse(GetText(this.Digits)); }
              | Call       = Id '(' Id Id ')'    { override Value = 42.0; }
              | Rounds     = '(' Expr ')'        { override Value = Expr.Value(); }
          
              precedence Additive:
              | Add        = Expr sm '+' sm Expr { override Value = Expr1.Value() + Expr2.Value(); }
              | Sub        = Expr sm '-' sm Expr { override Value = Expr1.Value() - Expr2.Value(); }
          
              precedence Multiplicative:
              | Mul        = Expr sm '*' sm Expr { override Value = Expr1.Value() * Expr2.Value(); }
              | Div        = Expr sm '/' sm Expr { override Value = Expr1.Value() / Expr2.Value(); }
              | Mod        = Expr sm '%' sm Expr { override Value = Expr1.Value() % Expr2.Value(); }
          
              precedence Power:
              | Pow        = Expr sm '^' sm Expr right-associative
                                                 { override Value = System.Math.Pow(Expr1.Value(), Expr2.Value()); }
          
              precedence Unary:
              | Neg        = '-' Expr            { override Value = -Expr.Value(); }
            }
          }

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


          1. NN1
            08.11.2022 08:55

            Это синтаксис описание языка, а сам язык можете хоть в стиле C сделать:

            https://github.com/rsdn/Nitra-Mini-C/blob/master/Samples/Fib/Fib/Fib.test

            http://rsdn.org/article/nitra/MiniC/Nitra-Mini-C.xml


            1. rsashka Автор
              08.11.2022 09:20

              Кхм... дело в том, что в данном случае аналогом NewLang будет сам(а?) Nitra и его синтаксис описание языка, а не результирующий абстрактный языка "для примера".


              1. NN1
                08.11.2022 09:26

                Моё дело показать похожую идею.

                Чтобы сделать язык, который умеет расширяться за счёт макросов как Nemerle, нужно вложить немало времени и сил.

                А сам синтаксис может быть каким-угодно.


                1. rsashka Автор
                  08.11.2022 09:32

                  Спасибо за ссылку. Синтаксис Nemerle очень похож на описание БНФ формы (а наверно она и есть, я не разбирался). И этаже форма записи используется и в других лексерах - парсерах.

                  И вы наверно удивитесь, но NewLang уже заимствовал из этой формы записи операторы определения терминов (::=).