Здравствуйте, Codealot, Вы писали:
C>Здравствуйте, Baiker, Вы писали:
B>>Где-то сейчас скулит один Влад — то ли от смеха, то ли от досады...
C>Влад очень радуется, что все заслуги приписали ему.
LVV>>1. От алгола-60 через виртовские язывки до Оберона-2 C>От оно как. То есть это не Алгол-60 важен, а оберон, который сделан на слямзенных из Алгола идеях.
"Огласите весь список, пожалуйста"(с)
Список идей, которые слямзены из Алгола-60.
Вы хотя бы сообщение об Алголе 60 читали ?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
LVV>>Вы хотя бы сообщение об Алголе 60 читали ? C>О том, что оберон-прародитель важнее всего, включая те языки, из которых растут ноги самого оберона?
То есть не читал но осуждаешь.
Книжки надо читать, родной.
Тогда сойдешь за умного.
Я читал сообщение еще до твоего рождения.
Алгол-60 — первый язык, синтаксис которого был описан грамматиками Хомского.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, SkyDance, Вы писали:
SD>Далее, язык программирования в современном понимании — не только синтаксис ключевых слов, но также runtime (зачастую в форме виртуальной машины), стандартная библиотека, менеджер зависимостей и прочие на первый взгляд не относящиеся к языку вещи. Но без них язык никому не нужен.
Для нового языка необязательно всё лисапедить с нуля, можно пристроиться к любой существующей инфраструктуре.
Например именно так развивался C++ (он компилировался в C).
Да и сейчас есть много примеров, например Hy — Lisp построенный на рантайме Python.
Создать новый язык в одно рыло вполне возможно меньше чем за месяц, но имеет это смысл только для специализированных задач, так что скорей всего это будет DSL. И при грамотном подходе такой язык вполне может обходить другие языки по целевым метрикам, именно за счёт специализации.
LVV>>Я читал сообщение еще до твоего рождения. C>Не надо так раздуваться, а то лопнешь.
То есть, про Алгол-60 сказать нечего...
И поэтому нечего возразить Кернигану и Доновану, которые проводят генеалогию Go от Алгола-60 до Оберона-2 напрямую
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, so5team, Вы писали:
s> Т.е. вы пропустили обвинения в сторону Java, которые около 20 лет назад любители Паскаля/Оберона выдвигали в сторону Java? Мол, разработчики Java внимательно изучали опыт Oberon-а и Component Pascal, даже кто-то к кому-то ездил в гости (уже не помню кто и куда), а потом бах! Выходит Java с байт-кодом , скомунизженным из Component Pascal, и ни одного благодарственного слова!
Это были не то чтобы обвинения, просто констатация факта, что жаба черпала идеи переносимого байт-кода в pascal-p (не обероне вовсе). Целая статья была на эту тему.
Здравствуйте, LaptevVV, Вы писали:
LVV>И поэтому нечего возразить Кернигану и Доновану, которые проводят генеалогию Go от Алгола-60 до Оберона-2 напрямую
То есть ровно то, что я и сказал. Оберон — промежуточное звено, а не родоначальник.
LVV>>И поэтому нечего возразить Кернигану и Доновану, которые проводят генеалогию Go от Алгола-60 до Оберона-2 напрямую C>То есть ровно то, что я и сказал. Оберон — промежуточное звено, а не родоначальник.
Ты так и не ответил, что Оберон слямзил у Алгола-60.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>>>И поэтому нечего возразить Кернигану и Доновану, которые проводят генеалогию Go от Алгола-60 до Оберона-2 напрямую C>>То есть ровно то, что я и сказал. Оберон — промежуточное звено, а не родоначальник. LVV>Ты так и не ответил, что Оберон слямзил у Алгола-60.
Оберон разве не "улучшенный" Паскаль, которому пришлось дать новое имя из-за отсутствия совместимости? А Паскаль прямой наследник Алгола-60. Немного "незаконнорожденный" потому как у папы слишком тяжелое отношение к законному ребенку — Алголу-68. И он родил вот такого вечного ребенка с названием Паскаль.
Здравствуйте, Shmj, Вы писали:
S>Вот если посмотреть популярные ЯП — то это дофига работы команд. Годы работы, годы доработок. Т.е. идея может быть вдохновлена одним человеком (на самом деле он эту идею где-то подсмотрел, как правило), а вот разработка языка — это уже только команда.
S>Получается хороший новый язык не может создать один человек и это всегда годы работы. Т.е. неожиданно новый ЯП возникнуть не может, в отличие от JS-фреймворка типа Vue.
S>Но бывают и исключения. Вот же наши как-то смогли создать тот же Nemerle вообще без особых затрат, силами энтузиастов. Как так?
В одиночку разработать свой ЯП я считаю возможным. Но трудности возникают когда приходится принять то или иное решение.
Это может быть и касательно синтаксиса, и касательно реализации, или установки неких ограничений.
Совместными усилиями, как мне кажется, результата можно добиться быстрее.
PHP изначально сделал Расмус. Классов там не было, их добавили позднее (в 5-ой версии), когда появилась команда разработчиков. Енумы там появились вообще относительно недавно (версия 8.1). Кстати имена переменных в PHP начинаются с символа $
Квадратные скобки там служат не только для обращения к элементу по индексу, но и для создания массива. Все массивы в PHP ассоциативны (как ключ допустимо и целое число и строка текста).
Я думаю многие задумывались поменять что-то в уже существующих ЯП, с которыми они работали, или что-то туда добавить. А не лучше ли вообще сделать своё? — Примерно такая идея у меня возникла ещё когда я учился в Колледже. Вам же это знакомо?
Я действительно хочу учавствовать в разработке нового ЯП!
Си++ хорош, но слишком переусложнён. Его стандартники делают с ним, то что хотят они — и это не всегда чего хотим мы.
Когда методы определяются внутри самого класса, то класс постепенно разрастается и превращается в монстра великана.
Мне кажется более наглядным, когда в программе данные определяются отдельно от действий над ними.
Я предлагаю создать свой язык вместе. У меня есть идеи, чтобы их обсудить.
Фичи языка:
*- Ячейка — это может быть: локальная переменная, параметр функции, свойство модуля, и т.д.
*- Возможность работать с типом, как со значением. Тип такой ячейки будет $type
*- Имена системных типов начинаются к примеру с символа $ (но это можно указать в конфиге, как и другие начальные символы).
Таким образом добавление системных типов не будет конфликтовать с уже написанным пользовательским кодом.
Тип может быть ключом ассоциативного массива, ведь его можно сравнивать с другим типом как просто значение.
t1 = $int
t2 = $float
t1 <> t2
*- Императивный кусок кода помещается в фигурные скобки и имеет тип $seq (sequence).
do = {
/* expression-list here */
}
Значение типа $seq можно передавать в функцию, присваивать в ячейку, и даже использовать как ключ в ассоциативном массиве.
Это позволит определять языковые конструкции как обычные функции.
Сами по себе фигурные скобки — действий внутри не выполняют без определённой команды. Это называется вычисление по требованию.
* По сути sequence — это как лямбда без параметров.
if_each!
[
{ a == b } : { /* действие 1 */ }
{ /* условие 2 */ } : { /* действие 2 */ }
]
if_first!
[
{ a == b } : { /* действие 1 */ }
{ /* условие 2 */ } : { /* действие 2 */ }
$bool.true : { /* действие иначе */ }
]
Квадратные скобки — массив/мапа. Двоеточие — разделитель в паре ключ-значение.
hint: думаю нужно отделить типы $map от $array
Символ восклицательный знак после ячейки с функцией — применить её к последующему выражению (просто чтобы не писать круглые скобки if_first([])).
if_first — выполняет sequence каждого условия до тех пор, пока не встретит первое правдивое, и тогда выполнит sequence действие из значения пары.
if_each — будет проверять все условия, даже после того как встретит правдивое.
Такая штука ведь нагляднее, чем городить огород из if else if else ?
Функцию вывода на консоль или в файл можно сделать чтобы она принимала sequence. Так она итератором будет вычислять элементы $seq — выражения, и выводить их результат, пока не они не закончатся, или не возникнет ощибка вывода / исключение, при которой оставшиеся выражения не будут вычислены.
@main
do = {
/* c-style function call */
@std.write( {sinus(a), " ", cosine(b)} )
/* Smarty style function call */
{sin(a), " ", cos(b)} |write@std
}
Собачка — начало имени модуля. Файл программы начинается с указания модуля. Далее следуют ячейки модуля — его свойства.
Это декларативная часть. Императивная часть находится внутри фигурных скобок.
При запуске программы выполнится sequence из ячеки do модуля @main
Запятая — разделитель опциональный.
Вертикальная палка перед ячейкой с функцией — применить функцию как метод к результату предшествующего выражения.
Так можно вызывать функции по цепочке слева-направо. Эта идея подсмотрена в PHP библиотеке шаблонов Smarty
a |sinus |write@std(to: file)
/* аналог: */
write@std(sinus(a), to: file)
-- line-comment
a |sinus => x |write_line@std(to: file)
write_line@std( x = sinus(a), to: file )
Оператор "присвоить вправо" => в общем то под вопросом.
Определение структур как типов: команда #struct
Команда #fn определяет функцию
Строчка: pos_2& |scale(0.5) передать яцейку pos_2 как link на ячейку (функция сможет её изменить)
Строчка: pos_1 |scale(2) запись в ячейку #ret в этом случае не изменит ячейку pos_1
Тут будут изменены свойства (x y) у координат в pos_1
Ведь структуры передаются по указателю, как и прочие значения системной категории _compound
Все категории типов (значение $cat) произрастают из базовой _any, включённой во все типы по-умолчанию.
Категория — это просто категория, она не хранит в себе данных. Каждый тип может принадлежать своему набору категорий.
В программе можно проверить их принадлежность. Это может быть полезно при динамической типизации.
При строгой типизации $cat можно использовать как ограничение (например ограничить тип параметра функции).
@sample
squared = #fn(_plain_number: n) { #ret = n*n }
do = {
i = 2 |squared
f = 1.5 |squared
}
@global
/* exposition only */
#cat (
_any /* base category */
_compound /* values of _compound types are passed by pointer */
_plain /* values of _plain types are passed by-value */
_number
_plain_number #includes( _plain _number )
)
_plain_number #refers_to ($int $float)
@lib
complex = #struct( re im )
complex #refers( _number )
Категории можно использовать как обычные значения в программе, их сравнивать, использовать как ключ в $map.
Ведь тип $cat пренадлежит категории _map_key
Естественно пользователь сможет определять и свои категории типов.
( _null / _undefined ) — пример для пустых значений при динамической типизации, возможно это системные категории.
Атрибуты
Например у всех типов есть атрибут initial — это начальное значение ячейки, которое будет использовано при неуказании инициализации.
Доступ к атрибутам происходит через оператор стрелка ->
range = #struct [$type: value_type] ( value_type: from, to )
range->initial(from: 0, to: value_type->max)
/* или */
range->initial.from = value_type->zero
range->initial.to = value_type->max
Что это? Да это же шаблон структуры. Параметр шаблона под именем value_type — тип.
А могло быть и число #struct [$type: Type, $int: N] ()
А мог быть и тип с ограничением $type_refers[_number]
А могла быть и категория с ограничением $cat_includes[_plain]
Собственно нужны ли категории и шаблоны в языке — под вопросом.
Про типизацию и название языка
Мне нравится название ksi-lang (и строгая и динамическая типизация)
ksi-script (только динамическая типизация)
ksi-pl (только строгая типизация)
Я долгое время пилю интерпретатор для ksi-script
Дело в том, что я по разным причинам откладывал разработку и возвращался к ней снова.
В одиночку непросто это.
Назначение языка — для любых целей. Хотя кси скрипт скорее всего для web, и как скриптовый движок в game-dev
p/s
Вопрос: синглтон или набор статик свойств
Ответ: вид значений #nest (это команда определиния типа)
colors = #nest (
red = 0h_ff0000
black = 0
)
/* colors.red |write */
Попытка создания значения типа, который nest only, приводит к получению этого же типа.
К струткуре можно добавить статик свойства командой #add_nest
@sample
color = #struct ( r g b a )
color->initial.a = 255
color #add_nest (
from_code = #fn($int: code) { /* вычисления */ }
red_color = color.from_code(colors.red)
)
Перечисления — они для чёткого набора состояний ячейки.
У элемента перечисления я думаю можно добавить атрибут data, чтобы там что-то хранить.
Атрибут data для каждого элемента перечисления привязан к этому элементу. Сами элементы передаются по значению-номеру (их data не копируется при этом).
align_h = #enum (left center right)
align_h.left->data = /* да тут что угодно, хоть даже структура */
do = {
a = align_h.center
a->data = /* what? can we change it? */
a->name |write_line@std
/* align_h.center->name */
}
Можно сделать атрибуты ->name ->index ->next_wrap (обсуждаемо)
А сомому енуму атрибут align_h->elements
В нюансах все прелести и сложности. Как делать захват локальных ячеек в sequence, который внутри sequence ? Всё ли захватывать, или указывать конкретные, или автоматом по необходимости (как в javascript).
Нужна ли языку константность (read_only ячейки)
$int: (c# = 5, x = 4, y# = c + x)
c += 1 /* ошибка */
Т.е при первом присвоении в имени ячейки окончание — спецсимвол из конфига.
В использовании имени в дальнейшем ридонли символ уже не указывается (чтобы не пришлось переписывать все места вручную, привет ide).
private public protected / friend — отдельная тема. Но я бы не тянул геттеры и сеттеры из си шарп
Наследование — сомнительно, но можно сделать команду #insert_struct
coords = #struct( x y )
game_object = #struct (
name
#insert_struct( coords )
type
)
Это позволит при интроспекции обходить свойства структуры именно в заданной последовательности. (В отличии от наследования, где сперва идёт база)
Доступ к под-объекту — как вариант в индексе [] тип
#cat ( _yes )
range = #options (
_any:
from
to
$cat_exact[_yes]:
exact_from
exact_to
)
r = range(to: 5, exact_to: _yes)
Оно хранит только заданные опции. Чтение из незаданных — вопрос. (или _null / _absent; либо ошибка/exception)
В отличии от $map — имена допустимых ключей явно заданы в определении.
Способ хранения данных — implementation defined
(наверно для $cat_exact можно по битам опции разложить, или придумать свой #bit_set / #flags)
Для системных функций я бы ещё сделал префикс &
&if_first &each &loop &write &switch &catch &throw
Так мы освобождаем имя модуля @std для прочих штук.
--
Для исключений (если да) — атрибуты: e->source.line e->source.column e->source.file
Получится собрать команду разработчиков нового языка программирования в этом году?
Какие идеи вам приглянулись?
pp/s Хотел сперва вкратце написать про ksi, чтож
Даже идею про #actions (аналог интерфейсам не показал)
do = {
c = 0h_e3d7f5 !as[color]
}
color = #struct ($integer_unsigned[8]: r g b)
color #allow_actions( conversion_from[_integer] )
conversion_from = #actions [$hint: from_type] (
as = #fn_params [$type: to_type] (from_type: this) : to_type
)
conversion_from[$int].as[color] = #fn (_integer: this) : color {
[#ret.r #ret.g #ret.b] = (this !make_byte_array: [3 2 1])
}
Ещё можно придумать команду #allow_actions_only, исключающую применение повторябельной #allow_actions
$hint = #variant( $type, $cat ) -- или как ещё это лучше сделать?? Чтобы оно могло принимать и тип, и категорию
Для GC я написал на плюсах optr (он учитывает цикличные линки), но пока его не тестировал сильно (версия-прототип)
И это не GC)
Здравствуйте, Sm0ke, Вы писали:
S>Я действительно хочу учавствовать в разработке нового ЯП!
Тогда давай начнёшь с определения целей.
1. Общая направленность — системный, прикладной на какой-то класс задач.
2. Процедурный, функциональный, что-то посредине.
3. Управление памятью: ручное (как в C, C++), автоматическое полностью (как в Java, C#), на владении ссылками (Rust), смешанное.
4. Уровень фиксации типизации — статическая, динамическая.
5. Уровень жёсткости типизации. Например, насколько разрешён integral promotion и по каким правилам.
Ответы желательно развёрнуто. Это только для разгона, после этого можно будет выходить на второй круг.
S>Си++ хорош, но слишком переусложнён. Его стандартники делают с ним, то что хотят они — и это не всегда чего хотим мы. S>Когда методы определяются внутри самого класса, то класс постепенно разрастается и превращается в монстра великана. S>Мне кажется более наглядным, когда в программе данные определяются отдельно от действий над ними.
Для большинства это менее наглядно, но пусть. Что-то похожее есть в Rust с его impl-ами для типа. Смотрел это? Какие впечатления?
S>Я предлагаю создать свой язык вместе. У меня есть идеи, чтобы их обсудить. S>Фичи языка: S>*- Ячейка — это может быть: локальная переменная, параметр функции, свойство модуля, и т.д.
Смущает термин "ячейка", но пусть.
S>*- Возможность работать с типом, как со значением. Тип такой ячейки будет $type S>*- Имена системных типов начинаются к примеру с символа $ (но это можно указать в конфиге, как и другие начальные символы).
Неееет!!!! Это однозначный путь к бардаку. Хватит нам и споров snake_case/CamelCase/mixedCase. Ты представляешь себе, что будет, если ты будешь подключать файл из одного такого режима к проекту с другим режимом?
Разрабатывая язык, сразу рассчитывай на то, что на нём будут писать что-то на миллион строк и половина авторов будут условными индусами, которым похер на всё, кроме зарплаты.
Подобные элементы синтаксиса обязаны быть жёсткими и безальтернативными!
S>Таким образом добавление системных типов не будет конфликтовать с уже написанным пользовательским кодом.
Для такого давно придумали пространства имён. Но редкие конфликты с автоматической переделкой — не проблема.
S>*- Императивный кусок кода помещается в фигурные скобки и имеет тип $seq (sequence).
Тогда надо сразу сказать, что будет в неимперативных кусках.
S>* По сути sequence — это как лямбда без параметров.
Только с автозахватом из внешнего контекста? Уточни.
S>Символ восклицательный знак после ячейки с функцией — применить её к последующему выражению (просто чтобы не писать круглые скобки if_first([])).
А зачем его вообще писать, ты ведь уже назвал "ячейку"?
S>if_first — выполняет sequence каждого условия до тех пор, пока не встретит первое правдивое, и тогда выполнит sequence действие из значения пары. S>if_each — будет проверять все условия, даже после того как встретит правдивое.
S>Такая штука ведь нагляднее, чем городить огород из if else if else ?
Да. Но сравнимо с тем, если будет явное elif.
S>Функцию вывода на консоль или в файл можно сделать чтобы она принимала sequence. Так она итератором будет вычислять элементы $seq — выражения, и выводить их результат, пока не они не закончатся, или не возникнет ощибка вывода / исключение, при которой оставшиеся выражения не будут вычислены.
Пока что вижу закос под пачку современных языков — что-то среднее между Zig и Ruby.
S>Запятая — разделитель опциональный.
Вместо LF или вообще? Надо уточнить.
S>coords = #struct ( x y )
Я бы делал, что есть набор слов, которые по умолчанию опознаются как ключевые (например if, while, func), а если нужно их сделать идентификаторами, то поставить, например, $ впереди.
S>Ячейка результата вызова функции #ret
По-моему, этот подход в основном признан менее удачным, чем явное return как оператор.
S>Ведь структуры передаются по указателю, как и прочие значения системной категории _compound
Это плохо. Например, математики тебя побьют. struct complex { float real, imag; } — во многих ABI передаётся в двух регистрах. Это эффективно. А ты предлагаешь откатиться обратно.
S>Все категории типов (значение $cat) произрастают из базовой _any, включённой во все типы по-умолчанию. S>Категория — это просто категория, она не хранит в себе данных. Каждый тип может принадлежать своему набору категорий. S>В программе можно проверить их принадлежность. Это может быть полезно при динамической типизации.
Интерфейсы или типажи (traits)? Есть причина вводить новое слово для того же?
S>Категории можно использовать как обычные значения в программе, их сравнивать, использовать как ключ в $map. S>Ведь тип $cat пренадлежит категории _map_key
Вообще обычно говорят более математически — hashable или linearly orderable.
S>Собственно нужны ли категории и шаблоны в языке — под вопросом.
Нужны. Только продумать надо.
Итого
У тебя нет killer feature. Без неё это не выйдет за пределы одного условного диссера.
Здравствуйте, netch80, Вы писали:
N>Тогда давай начнёшь с определения целей.
N>1. Общая направленность — системный, прикладной на какой-то класс задач.
Назначение языка — для любых задач.
И для gui, и для научных расчётов, и как встроенный скриптовый движок приложений/игр.
N>2. Процедурный, функциональный, что-то посредине.
Наверно это микс.
Структура файла:
* Имя модуля
* Декларативная часть (определение ячеек модуля, то есть свойств модуля)
Элемент декларативной части начинается с имени ячейки, или с разрешённой для декларативной части команды.
Ячейка может содержать что угодно. И тип, и функцию, и последовательность выражений (sequence), и просто значение
Таким образом не нужно писать как в си++ using type_alias = int;
А просто type_alias = $int
Аналогично для функций:
fn_alias = other_fn
S>>*- Императивный кусок кода помещается в фигурные скобки и имеет тип $seq (sequence). N>Тогда надо сразу сказать, что будет в неимперативных кусках.
В декларативной части можно:
имя_ячейки = ( /* expression */ )
имя_ячейки = /* команда опеделения */
имя_ячейки = { /* последовательность выражений, тут императивная часть */ }
имя_ячейки /* команда-модификатор */
Вот некоторые команды для создания новых определений: (список не полный)
#struct
#enum
#fn
#nest
#actions // интерфейс, набор методов
N>3. Управление памятью: ручное (как в C, C++), автоматическое полностью (как в Java, C#), на владении ссылками (Rust), смешанное.
Этот нюанс хорошо бы обсудить отдельно.
Для динамических объектов я думаю, что по умолчанию будет реализация optr (автоматическое освобождение ресурсов)
Вообще неплохо-бы предусмотреть способ указания (в самой программе на кси) для желаемого поведения при конкретном случае (для low level штук).
Например чтобы не происходило автоосвобождение большого колличества мелких объектов по отдельности, а пачкой
(ещё когда при закрытии приложении ОС сама освобождает выделенную память)
N>4. Уровень фиксации типизации — статическая, динамическая.
Все Три вида типизации: ~ по трём отдельным обработчикам
Можно сказать — три диалекта языка.
Каждый обработчик может быть как компилятор, так и интерпретатор. А может быть два в одном.
Это уже нюанс реализации обработчика.
N>5. Уровень жёсткости типизации. Например, насколько разрешён integral promotion и по каким правилам.
СИ-шных ошибок в проектировании языка желательно избежать!
Есть шаблонный метод x !as[type] , который вызывается в программе-скрипте явно для преобразования типов.
В квадратных скобках указывается параметр шаблона — тип результата преобразования.
Методы в кси вызываются не через точку (а через воскл.знак перед методом).
Точка служит для обращения к элементам (свойствам).
А методы задаются отдельно в так называемом интерфейсе (команда #actions)
conversion_from = #actions [Source_type] (
as = #fn_params [Target_type] (Source_type: src) : Target_type
implicit_as = #fn_params [Target_type] (Source_type: src) : Target_type
/* implicit_as = as */
/* same params of function */
)
Рассмотрим на примере. Если мы хотим преобразование явного вида из $int в $float тогда в декларативной части:
$float #allow_actions( conversion_from[$int] )
conversion_from[$int].as[$float] = #fn ($int: number) : $float
{ #ret = /* какая-то системная функция */ }
do = {
i = 5
f = (i !as[$float])
}
Если действие implicit_as не задано, то неявное преобразование запрещено обработчиком.
Но мы можем при желании его задать одной строчкой:
Короче сделать алиас из уже написанной функции implicit_as = as
В этом случае будет работать неявное преобразование. Программист это может контролировать сам в том числе и для своих типов.
N>Ответы желательно развёрнуто. Это только для разгона, после этого можно будет выходить на второй круг.
S>>Мне кажется более наглядным, когда в программе данные определяются отдельно от действий над ними. N>Для большинства это менее наглядно, но пусть. Что-то похожее есть в Rust с его impl-ами для типа. Смотрел это? Какие впечатления?
Надо будет посмотреть как там impl в Rust
S>>*- Имена системных типов начинаются к примеру с символа $ (но это можно указать в конфиге, как и другие начальные символы).
N>Неееет!!!! Это однозначный путь к бардаку. Хватит нам и споров snake_case/CamelCase/mixedCase. Ты представляешь себе, что будет, если ты будешь подключать файл из одного такого режима к проекту с другим режимом?
N>Подобные элементы синтаксиса обязаны быть жёсткими и безальтернативными!
Согласен с этим утверждением. Я не точно сформулировал мысль.
Начальные символы для системных штук указываются в конфиге обработчика, а не пользовательского проекта.
Или жестко заданы внутри компилятора (это нюанс реализации, да)
S>>coords = #struct ( x y )
N>Я бы делал, что есть набор слов, которые по умолчанию опознаются как ключевые (например if, while, func), а если нужно их сделать идентификаторами, то поставить, например, $ впереди.
#struct — это системная команда.
Какой начальный символ для команд, а какой для системных типов лучше подобрать?
Я предлагаю для команд #
Для типов $
Для функций &
Это просто строчки в конфиге обоаботчика. С другой стороны нужен общепринятый формат)
Ключевые слова? keywords — нужны ли они вообще в кси? Если да, то какие?
Можно сделать bitwise методы для integer types (выглядят как именованные операторы bit_xor, bit_and, bit_shift +1 -1)
S>>Таким образом добавление системных типов не будет конфликтовать с уже написанным пользовательским кодом.
N>Для такого давно придумали пространства имён. Но редкие конфликты с автоматической переделкой — не проблема.
В кси — модули. Хотя пространства имён возможно тоже понадобятся (или нет). Есть #nest для nested штук. @sys.int просто $int писать не так длинно @sys.write_line или &write_line
S>>* По сути sequence — это как лямбда без параметров. N>Только с автозахватом из внешнего контекста? Уточни.
Да, с автозахватом (closure)
Мб добавить возможность задания seq без захвата локального внешнего контекста через конструкцию #{ } ?
S>>Символ восклицательный знак после ячейки с функцией — применить её к последующему выражению (просто чтобы не писать круглые скобки if_first([])).
N>А зачем его вообще писать, ты ведь уже назвал "ячейку"?
Но тут нюанс с !else пока не решён)
S>>Запятая — разделитель опциональный. N>Вместо LF или вообще? Надо уточнить.
LF и запятая — опциональные разделители, хотя LF оно как WHITEPSACE
А запятая с проверкой в парсере.
S>>Ячейка результата вызова функции #ret N>По-моему, этот подход в основном признан менее удачным, чем явное return как оператор.
Добавить команду #return не проблема)
S>>Ведь структуры передаются по указателю, как и прочие значения системной категории _compound
N>Это плохо. Например, математики тебя побьют. struct complex { float real, imag; } — во многих ABI передаётся в двух регистрах. Это эффективно. А ты предлагаешь откатиться обратно.
Значит нужна возможность задать для структуры как она передаётся ( _by_value или _by_pointer )
Например через категории типов.
@math
complex = #struct ( $float: real imag )
complex #refers ( _by_value ) // привязали категорию для типа
S>>Все категории типов (значение $cat) произрастают из базовой _any, включённой во все типы по-умолчанию. S>>Категория — это просто категория, она не хранит в себе данных. Каждый тип может принадлежать своему набору категорий. S>>В программе можно проверить их принадлежность. Это может быть полезно при динамической типизации.
N>Интерфейсы или типажи (traits)? Есть причина вводить новое слово для того же?
Нет, это не интерфейсы. Про интерфейсы я ответил выше как #actions
Категории ещё могут быть абстрактными (с запретом к привязки для типов)
Для специальных значений, или сигналов об ошибке.
S>>Собственно нужны ли категории и шаблоны в языке — под вопросом. N>Нужны. Только продумать надо.
S>>Категории можно использовать как обычные значения в программе, их сравнивать, использовать как ключ в $map. S>>Ведь тип $cat пренадлежит категории _map_key
N>Вообще обычно говорят более математически — hashable или linearly orderable.
Это похоже на набор методов для работы с данными.
Стандыртные наборы действий (интерфейсы) для системных типов необходимо определить.
Желательно совместными усилиями, а не в одиночку.
N>Итого N>У тебя нет killer feature. Без неё это не выйдет за пределы одного условного диссера.
А как-же работа с типами как с обычными значениями?
Вместо плюсовых <type_traits> std::is_same_v<> и using type =
А как же встроенная система атрибутов. Позволяющая в том числе и рефлексию (интроспекцию).
Работать со списком/мапой элементов перечисления, как с обычным массивом.
Так-же со списком свойств структуры / неста.
Атрибут type->name текстовая строка.
Возможность добавлять пользовательские конструкции над seq как функции.
--
Постораюсь ответить на вопросы, которые ещё остались неотвечены.
То что я написал — моё приблизительное представление.
На основе этого можно же сделать better language, как бы он не назывался
Здравствуйте, Sm0ke, Вы писали:
N>>1. Общая направленность — системный, прикладной на какой-то класс задач. S>Назначение языка — для любых задач.
Уже не бывает. Надо определиться.
S>И для gui, и для научных расчётов, и как встроенный скриптовый движок приложений/игр.
N>>2. Процедурный, функциональный, что-то посредине.
S>Наверно это микс.
S>Структура файла: S>* Имя модуля S>* Декларативная часть (определение ячеек модуля, то есть свойств модуля)
S>Элемент декларативной части начинается с имени ячейки, или с разрешённой для декларативной части команды. S>Ячейка может содержать что угодно. И тип, и функцию, и последовательность выражений (sequence), и просто значение
S>Таким образом не нужно писать как в си++ using type_alias = int; S>А просто type_alias = $int S>Аналогично для функций: S>
S>fn_alias = other_fn
S>
Ничего из этого пока что не даёт функциональный язык. Вижу процедурщину в чистом виде. Это не плохо, но это характерно.
S>>>*- Императивный кусок кода помещается в фигурные скобки и имеет тип $seq (sequence). N>>Тогда надо сразу сказать, что будет в неимперативных кусках.
S>В декларативной части можно: S>
S>имя_ячейки = ( /* expression */ )
S>имя_ячейки = /* команда опеделения */
S>имя_ячейки = { /* последовательность выражений, тут императивная часть */ }
S>имя_ячейки /* команда-модификатор */
S>
Это просто вынесенная вперёд часть инициализаций, ничего пока особенного.
N>>3. Управление памятью: ручное (как в C, C++), автоматическое полностью (как в Java, C#), на владении ссылками (Rust), смешанное.
S>Этот нюанс хорошо бы обсудить отдельно.
Не "отдельно", а с него надо начинать.
Потому что если язык вообще позволяет произвольные игры с указателями, типа сохранить после удаления объекта, то нет смысла и запрещать их произвольное создание.
Язык с ManMM это переносимый ассемблер (даже если это C++). Язык с AMM это то, что требует как минимум unsafe-слоя для реализации и связи с нижними слоями.
Попытка их совместить — см. про коня и лань.
S>Вообще неплохо-бы предусмотреть способ указания (в самой программе на кси) для желаемого поведения при конкретном случае (для low level штук). S>Например чтобы не происходило автоосвобождение большого колличества мелких объектов по отдельности, а пачкой
Это речь про GC. Разные стили GC могут выбираться по реализации, но в этом нет ничего нового.
S>(ещё когда при закрытии приложении ОС сама освобождает выделенную память)
N>>4. Уровень фиксации типизации — статическая, динамическая.
S>Все Три вида типизации: ~ по трём отдельным обработчикам S>Можно сказать — три диалекта языка.
S> Динамическая типизация ~ ksi-script S> Строгая типизация ~ ksi-pl S> динамическая + строгая ~ ksi-lang
Почему это динамическая+строгая?
S>Каждый обработчик может быть как компилятор, так и интерпретатор. А может быть два в одном. S>Это уже нюанс реализации обработчика.
N>>5. Уровень жёсткости типизации. Например, насколько разрешён integral promotion и по каким правилам.
S>СИ-шных ошибок в проектировании языка желательно избежать!
Только вначале разобраться, что там ошибки, что — последствия ограничений реализации, а что — полезные фишки, облегчающие (обычно) жизнь программисту.
S>Есть шаблонный метод x !as[type] , который вызывается в программе-скрипте явно для преобразования типов.
Всегда? Безопасные (без изменения характера типа и без потери точности) расширения вообще не допускаются?
S>Рассмотрим на примере. Если мы хотим преобразование явного вида из $int в $float тогда в декларативной части: S>
S>$float #allow_actions( conversion_from[$int] )
S>conversion_from[$int].as[$float] = #fn ($int: number) : $float
S>{ #ret = /* какая-то системная функция */ }
S>do = {
S> i = 5
S> f = (i !as[$float])
S>}
S>
Я не понял, к чему '!' впереди "!as". В остальном — понятно на локальном уровне. Но мне кажется, что безусловный запрет расширяющих конверсий это диверсия.
Если нужно, их следует запрещать для определённых контекстов. Но я думаю, это будет редко использоваться.
Кстати, int->float для стандартных int32 и binfloat32 это не расширяющая конверсия, возможна потеря точности.
N>>Подобные элементы синтаксиса обязаны быть жёсткими и безальтернативными!
S>Согласен с этим утверждением. Я не точно сформулировал мысль. S>Начальные символы для системных штук указываются в конфиге обработчика, а не пользовательского проекта. S>Или жестко заданы внутри компилятора (это нюанс реализации, да)
Скорее жёстко, тут нечего конфигурировать.
S>#struct — это системная команда. S>Какой начальный символ для команд, а какой для системных типов лучше подобрать? S>Я предлагаю для команд # S>Для типов $ S>Для функций &
А зачем выделять типы и функции? Это необычно.
S>Это просто строчки в конфиге обоаботчика. С другой стороны нужен общепринятый формат) S>Ключевые слова? keywords — нужны ли они вообще в кси? Если да, то какие?
У меня такое впечатление, что вы их называете командами.
S>Можно сделать bitwise методы для integer types (выглядят как именованные операторы bit_xor, bit_and, bit_shift +1 -1)
Можно.
S>>>Таким образом добавление системных типов не будет конфликтовать с уже написанным пользовательским кодом.
N>>Для такого давно придумали пространства имён. Но редкие конфликты с автоматической переделкой — не проблема.
S>В кси — модули. Хотя пространства имён возможно тоже понадобятся (или нет).
Если хочется чего-то выше уровня песочницы — понадобятся, иерархические.
S>>>* По сути sequence — это как лямбда без параметров. N>>Только с автозахватом из внешнего контекста? Уточни. S>Да, с автозахватом (closure)
Если не регулируется — могут жаловаться.
S>Мб добавить возможность задания seq без захвата локального внешнего контекста через конструкцию #{ } ?
Тогда в ней можно и думать писать явный список для захвата.
S>Ключевых слов в кси стараюсь вообще избегать.
Совсем избежать не получится.
Префиксовать все — возможно, есть такие стили, но обычно пользователи жалуются.
S>К примеру можно определить системную функцию &do_while цикл с пост-условием
Есть такие стили, да. Можно посмотреть на Common LISP как образчик. Там макрами транслируется часть конструкций в другой код.
S>Значит нужна возможность задать для структуры как она передаётся ( _by_value или _by_pointer )
Да. И умолчание скорее by value.
N>>Интерфейсы или типажи (traits)? Есть причина вводить новое слово для того же?
S>Нет, это не интерфейсы. Про интерфейсы я ответил выше как #actions S>Категории ещё могут быть абстрактными (с запретом к привязки для типов) S>Для специальных значений, или сигналов об ошибке.
Ближе к типажам, наверно.
N>>Вообще обычно говорят более математически — hashable или linearly orderable. S>Это похоже на набор методов для работы с данными. S>
Ну да, дальше определяется, что например hashable должен поддерживать hash(), а linearly orderable — сравнение как минимум на "меньше" (и полезно на "равно", судя по <=> в новом C++).
S>Стандыртные наборы действий (интерфейсы) для системных типов необходимо определить. S>Желательно совместными усилиями, а не в одиночку.
N>>Итого N>>У тебя нет killer feature. Без неё это не выйдет за пределы одного условного диссера.
S>А как-же работа с типами как с обычными значениями? S>Вместо плюсовых <type_traits> std::is_same_v<> и using type =
По сравнению с плюсами — может быть. По сравнению с более новыми языками — нет.
S>А как же встроенная система атрибутов. Позволяющая в том числе и рефлексию (интроспекцию).
Аналогично.
Глубоко изучи для начала Rust.
S>Возможность добавлять пользовательские конструкции над seq как функции.
S>--
S>Постораюсь ответить на вопросы, которые ещё остались неотвечены.
S>То что я написал — моё приблизительное представление. S>На основе этого можно же сделать better language, как бы он не назывался
Можно. Но без хорошей теоретической подготовки шансы около нуля.