Pull to refresh

Comments 51

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

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

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

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

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

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

UFO just landed and posted this here

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

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

UFO just landed and posted this here

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

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

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

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

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

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

Есть небольшая разница, нужно ли мне писать этот символ иногда, чтобы подчеркнуть какую-нибудь особенность типа 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) {}

Вообще то в приведенных вами примерах, косая черта перед термином обязательно будет всего в одном месте, перед 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); 
};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/::New<->/:Lang:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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(); }
  }
}

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

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

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

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

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

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

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

Sign up to leave a comment.

Articles