Сообщение Re[3]: стоит создать ЯП? от 11.10.2023 12:57
Изменено 11.10.2023 13:41 Sm0ke
Re[3]: стоит создать ЯП?
Здравствуйте, netch80, Вы писали:
N>Тогда давай начнёшь с определения целей.
N>1. Общая направленность — системный, прикладной на какой-то класс задач.
Назначение языка — для любых задач.
И для gui, и для научных расчётов, и как встроенный скриптовый движок приложений/игр.
N>2. Процедурный, функциональный, что-то посредине.
Наверно это микс.
Структура файла:
* Имя модуля
* Декларативная часть (определение ячеек модуля, то есть свойств модуля)
Элемент декларативной части начинается с имени ячейки, или с разрешённой для декларативной части команды.
Ячейка может содержать что угодно. И тип, и функцию, и последовательность выражений (sequence), и просто значение
Таким образом не нужно писать как в си++ using type_alias = int;
А просто type_alias = $int
Аналогично для функций:
S>>*- Императивный кусок кода помещается в фигурные скобки и имеет тип $seq (sequence).
N>Тогда надо сразу сказать, что будет в неимперативных кусках.
В декларативной части можно:
Вот некоторые команды для создания новых определений: (список не полный)
N>3. Управление памятью: ручное (как в C, C++), автоматическое полностью (как в Java, C#), на владении ссылками (Rust), смешанное.
Этот нюанс хорошо бы обсудить отдельно.
Для динамических объектов я думаю, что по умолчанию будет реализация optr (автоматическое освобождение ресурсов)
Вообще неплохо-бы предусмотреть способ указания (в самой программе на кси) для желаемого поведения при конкретном случае (для low level штук).
Например чтобы не происходило автоосвобождение большого колличества мелких объектов по отдельности, а пачкой
(ещё когда при закрытии приложении ОС сама освобождает выделенную память)
N>4. Уровень фиксации типизации — статическая, динамическая.
Это уже нюанс реализации обработчика.
N>5. Уровень жёсткости типизации. Например, насколько разрешён integral promotion и по каким правилам.
СИ-шных ошибок в проектировании языка желательно избежать!
Есть шаблонный метод x !as[type] , который вызывается в программе-скрипте явно для преобразования типов.
В квадратных скобках указывается параметр шаблона — тип результата преобразования.
Методы в кси вызываются не через точку (а через воскл.знак перед методом).
Точка служит для обращения к элементам (свойствам).
А методы задаются отдельно в так называемом интерфейсе (команда #actions)
Рассмотрим на примере. Если мы хотим преобразование явного вида из $int в $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>А зачем его вообще писать, ты ведь уже назвал "ячейку"?
Ячейка if_first хранит функцию. Способы вызова функции:
Функции if_first if_each принимают один параметр, с типом $seq
Я бы по хорошему их сделал системными.
Ключевых слов в кси стараюсь вообще избегать.
К примеру можно определить системную функцию &do_while цикл с пост-условием
Или как метод в seq_actions
Вместо if можно сделать метод !then
Но тут нюанс с !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 )
Например через категории типов.
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, как бы он не назывался
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. Уровень фиксации типизации — статическая, динамическая.
Каждый обработчик может быть как компилятор, так и интерпретатор. А может быть два в одном.Все Три вида типизации: ~ по трём отдельным обработчикам
Можно сказать — три диалекта языка.
Динамическая типизация ~ ksi-script
Строгая типизация ~ ksi-pl
динамическая + строгая ~ ksi-lang
Это уже нюанс реализации обработчика.
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 не задано, то неявное преобразование запрещено обработчиком.
Но мы можем при желании его задать одной строчкой:
conversion_from[$int].implicit_as[$float] = conversion_from[$int].as[$float]
Короче сделать алиас из уже написанной функции 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>А зачем его вообще писать, ты ведь уже назвал "ячейку"?
Ячейка if_first хранит функцию. Способы вызова функции:
- sinus(p)
sinus! p
p |sinus
p |some_fn(second_param, third_param)
p |some_fn: second_param
Функции if_first if_each принимают один параметр, с типом $seq
Я бы по хорошему их сделал системными.
Ключевых слов в кси стараюсь вообще избегать.
К примеру можно определить системную функцию &do_while цикл с пост-условием
@global /* exposition only */
&do_while = #fn($seq: loop_body, condition)
@main
do = {
{ /* loop body */ } |&do_while: { /* condition */ }
}
Или как метод в seq_actions
@main
do = {
{ /* loop body */ } !do_while: { /* post-condition */ }
{ /* pre-condition */ } !while_do: { /* loop body */ }
}
@global /* system exposition */
seq_actions = #actions ( do_while, while_do )
Вместо if можно сделать метод !then
{ a == b } !then: { seq }
Но тут нюанс с !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
Категории ещё могут быть абстрактными (с запретом к привязки для типов)
Для специальных значений, или сигналов об ошибке.
@sample
// returns: _key_absent or _ok
func1 = #fn (param) : $cat_options[_key_absent, _ok]
{ #ret = _ok }
// returns: subcategories of _null
func2 = #fn (param) : $cat_under[_null]
{ #ret = _ok }
@global
#cats (
_null #includes ( _abstract )
_null #subcat ( _undefined _key_absent _no_such_action _ok )
)
@maybe
void_type = $cat_exact[_ok]
S>>Собственно нужны ли категории и шаблоны в языке — под вопросом.
N>Нужны. Только продумать надо.
S>>Категории можно использовать как обычные значения в программе, их сравнивать, использовать как ключ в $map.
S>>Ведь тип $cat пренадлежит категории _map_key
N>Вообще обычно говорят более математически — hashable или linearly orderable.
Это похоже на набор методов для работы с данными.
ordering = #enum ( strong weak partial )
cmp_result = /* ? */
comparable = #actions [ordering: O, $type: left_type right_type] (
cmp = #fn_params (left_type: left, right_type: right) : cmp_result
(<) = #fn (left_type: left, right_type: right)
{ #return( (left !cmp: right) == cmp_result.less ) }
)
Стандыртные наборы действий (интерфейсы) для системных типов необходимо определить.
Желательно совместными усилиями, а не в одиночку.
N>Итого
N>У тебя нет killer feature. Без неё это не выйдет за пределы одного условного диссера.
А как-же работа с типами как с обычными значениями?
Вместо плюсовых <type_traits> std::is_same_v<> и using type =
А как же встроенная система атрибутов. Позволяющая в том числе и рефлексию (интроспекцию).
Работать со списком/мапой элементов перечисления, как с обычным массивом.
Так-же со списком свойств структуры / неста.
Атрибут type->name текстовая строка.
Возможность добавлять пользовательские конструкции над seq как функции.
--
Постораюсь ответить на вопросы, которые ещё остались неотвечены.
То что я написал — моё приблизительное представление.
На основе этого можно же сделать better language, как бы он не назывался
Re[3]: стоит создать ЯП?
Здравствуйте, netch80, Вы писали:
N>Тогда давай начнёшь с определения целей.
N>1. Общая направленность — системный, прикладной на какой-то класс задач.
Назначение языка — для любых задач.
И для gui, и для научных расчётов, и как встроенный скриптовый движок приложений/игр.
N>2. Процедурный, функциональный, что-то посредине.
Наверно это микс.
Структура файла:
* Имя модуля
* Декларативная часть (определение ячеек модуля, то есть свойств модуля)
Элемент декларативной части начинается с имени ячейки, или с разрешённой для декларативной части команды.
Ячейка может содержать что угодно. И тип, и функцию, и последовательность выражений (sequence), и просто значение
Таким образом не нужно писать как в си++ using type_alias = int;
А просто type_alias = $int
Аналогично для функций:
S>>*- Императивный кусок кода помещается в фигурные скобки и имеет тип $seq (sequence).
N>Тогда надо сразу сказать, что будет в неимперативных кусках.
В декларативной части можно:
Вот некоторые команды для создания новых определений: (список не полный)
N>3. Управление памятью: ручное (как в C, C++), автоматическое полностью (как в Java, C#), на владении ссылками (Rust), смешанное.
Этот нюанс хорошо бы обсудить отдельно.
Для динамических объектов я думаю, что по умолчанию будет реализация optr (автоматическое освобождение ресурсов)
Вообще неплохо-бы предусмотреть способ указания (в самой программе на кси) для желаемого поведения при конкретном случае (для low level штук).
Например чтобы не происходило автоосвобождение большого колличества мелких объектов по отдельности, а пачкой
(ещё когда при закрытии приложении ОС сама освобождает выделенную память)
N>4. Уровень фиксации типизации — статическая, динамическая.
Это уже нюанс реализации обработчика.
N>5. Уровень жёсткости типизации. Например, насколько разрешён integral promotion и по каким правилам.
СИ-шных ошибок в проектировании языка желательно избежать!
Есть шаблонный метод x !as[type] , который вызывается в программе-скрипте явно для преобразования типов.
В квадратных скобках указывается параметр шаблона — тип результата преобразования.
Методы в кси вызываются не через точку (а через воскл.знак перед методом).
Точка служит для обращения к элементам (свойствам).
А методы задаются отдельно в так называемом интерфейсе (команда #actions)
Рассмотрим на примере. Если мы хотим преобразование явного вида из $int в $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>А зачем его вообще писать, ты ведь уже назвал "ячейку"?
Ячейка if_first хранит функцию. Способы вызова функции:
Функции if_first if_each принимают один параметр, с типом $seq
Я бы по хорошему их сделал системными.
Ключевых слов в кси стараюсь вообще избегать.
К примеру можно определить системную функцию &do_while цикл с пост-условием
Или как метод в seq_actions
Вместо if можно сделать метод !then
Но тут нюанс с !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 )
Например через категории типов.
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, как бы он не назывался
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. Уровень фиксации типизации — статическая, динамическая.
Каждый обработчик может быть как компилятор, так и интерпретатор. А может быть два в одном.Все Три вида типизации: ~ по трём отдельным обработчикам
Можно сказать — три диалекта языка.
Динамическая типизация ~ ksi-script
Строгая типизация ~ ksi-pl
динамическая + строгая ~ ksi-lang
Это уже нюанс реализации обработчика.
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 не задано, то неявное преобразование запрещено обработчиком.
Но мы можем при желании его задать одной строчкой:
conversion_from[$int].implicit_as[$float] = conversion_from[$int].as[$float]
Короче сделать алиас из уже написанной функции 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>А зачем его вообще писать, ты ведь уже назвал "ячейку"?
Ячейка if_first хранит функцию. Способы вызова функции:
- sinus(p)
sinus! p
p |sinus
p |some_fn(second_param, third_param)
p |some_fn: second_param
Функции if_first if_each принимают один параметр, с типом $seq
Я бы по хорошему их сделал системными.
Ключевых слов в кси стараюсь вообще избегать.
К примеру можно определить системную функцию &do_while цикл с пост-условием
@global /* exposition only */
&do_while = #fn($seq: loop_body, condition)
@main
do = {
{ /* loop body */ } |&do_while: { /* condition */ }
}
Или как метод в seq_actions
@main
do = {
{ /* loop body */ } !do_while: { /* post-condition */ }
{ /* pre-condition */ } !while_do: { /* loop body */ }
}
@global /* system exposition */
seq_actions = #actions ( do_while, while_do )
Вместо if можно сделать метод !then
{ a == b } !then: { seq }
Но тут нюанс с !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
Категории ещё могут быть абстрактными (с запретом к привязки для типов)
Для специальных значений, или сигналов об ошибке.
@sample
// returns: _key_absent or _ok
func1 = #fn (param) : $cat_options[_key_absent, _ok]
{ #ret = _ok }
// returns: subcategories of _null
func2 = #fn (param) : $cat_under[_null]
{ #ret = _ok }
@global
#cats (
_null #includes ( _abstract )
_null #subcat ( _undefined _key_absent _no_such_action _ok )
)
@maybe
void_type = $cat_exact[_ok]
S>>Собственно нужны ли категории и шаблоны в языке — под вопросом.
N>Нужны. Только продумать надо.
S>>Категории можно использовать как обычные значения в программе, их сравнивать, использовать как ключ в $map.
S>>Ведь тип $cat пренадлежит категории _map_key
N>Вообще обычно говорят более математически — hashable или linearly orderable.
Это похоже на набор методов для работы с данными.
ordering = #enum ( strong weak partial )
cmp_result = /* ? */
comparable = #actions [ordering: O, $type: left_type right_type] (
cmp = #fn_params (left_type: left, right_type: right) : cmp_result
(<) = #fn (left_type: left, right_type: right) : $bool
{ #return( (left !cmp: right) == cmp_result.less ) }
)
Стандыртные наборы действий (интерфейсы) для системных типов необходимо определить.
Желательно совместными усилиями, а не в одиночку.
N>Итого
N>У тебя нет killer feature. Без неё это не выйдет за пределы одного условного диссера.
А как-же работа с типами как с обычными значениями?
Вместо плюсовых <type_traits> std::is_same_v<> и using type =
А как же встроенная система атрибутов. Позволяющая в том числе и рефлексию (интроспекцию).
Работать со списком/мапой элементов перечисления, как с обычным массивом.
Так-же со списком свойств структуры / неста.
Атрибут type->name текстовая строка.
Возможность добавлять пользовательские конструкции над seq как функции.
--
Постораюсь ответить на вопросы, которые ещё остались неотвечены.
То что я написал — моё приблизительное представление.
На основе этого можно же сделать better language, как бы он не назывался