LINUX.ORG.RU
ФорумTalks

Встречайте очередную замену Си

 ,


0

8

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

https://drewdevault.com/2021/03/19/A-new-systems-language.html

use io;

export fn main() void = {
	const greetings = [
		"Hello, world!",
		"¡Hola Mundo!",
		"Γειά σου Κόσμε!",
		"Привет мир!",
		"こんにちは世界!",
	];
	for (let i = 0z; i < len(greetings); i += 1) {
		io::println(greetings[i]);
	};
};

По сравнению с Си:

  • More robust error handling via tagged unions
  • Improved, Unicode-aware string support
  • Memory safe array, slice, and pointer types (and unsafe versions, if needed)
  • Direct compatibility with the C ABI for trivial C interop
  • A simpler, context-free, expression-oriented syntax
  • A standard library free of the constraints of POSIX or the C standard
★★★

Последнее исправление: dadd (всего исправлений: 1)

КПК не одобряет заголовок

bender ★★★★★
()
Ответ на: комментарий от X512

ELF это умеет

А в PE это явно надо проделывать, иначе вызов библиотечной функции будет сначала читать адрес из таблицы. Так что для ЯП не особо подходит

SR_team ★★★★★
()
Ответ на: комментарий от X512

Мы наверно о разном, потому что у меня MinGW всегда так делал: https://nc.sr.team/s/AYaFE5WxBbqtXqR Т.е. по адресу 0x62c305c8 записан адрес функции RegCloseKey, и при вызове сначала происходит чтение из таблицы в секции .idata, где 0x62c305c8 это одна из записей.

SR_team ★★★★★
()
Последнее исправление: SR_team (всего исправлений: 1)
Ответ на: комментарий от X512

Оберон так и работает. Каждый исходник компилируется в отдельный динамически загружаемый исполняемый файл. Таких модулей загружаются сотни и более и всё быстро стартует и работает. Причём даже на очень слабом железе таком как Apple Macintosh 128K или ранних 32 битных процессорах

Я не нахожу в гугле подтверждений твоим словам. Точнее, я не нахожу ничего про линкер Оберона вообще.

O(log(n)). Бинарный поиск в отсортированном массиве символов

O(N log(N)) для всей программы при условии импорта всех символов. А если учесть, что по мере роста программы линейно увеличивается число модулей. использующих этот модуль, то получается O(N*M log(N)) — квадратичная сложность, что есть полный отсос.

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

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

byko3y ★★★★
()
Ответ на: комментарий от thunar

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

uin ★★★
()
Последнее исправление: uin (всего исправлений: 1)
Ответ на: комментарий от byko3y

Я не нахожу в гугле подтверждений твоим словам.

https://en.wikipedia.org/wiki/Ceres_(workstation)

Точнее, я не нахожу ничего про линкер Оберона вообще.

Вот исходник динамического загрузчика: StdLoader. Вообще исходники и документация Оберона плохо гуглятся, потому что они в бинарном формате по типу *.doc у MS Word.

А если учесть, что по мере роста программы линейно увеличивается число модулей. использующих этот модуль, то получается O(N*M log(N)) — квадратичная сложность, что есть полный отсос.

Не знаю что у вас за расчёты, но у меня Оберон система с GUI и около сотни модулей запускается за миллисекунды. В разы быстрее многих поделок на C/C++.

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

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

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 2)

Дрю Деволт объявил

Кто такой, чем знаменит?

ahdenchik
()
Ответ на: комментарий от SR_team

Ответ на: комментарий от uin 20.03.21 20:21:17

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

thunar

Ответ на: комментарий от thunar 20.03.21 21:43:18

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

uin

imatveev13
()
Ответ на: комментарий от next_time

почему вам показалось, что речь о языках низкого уровня?

vaddd ★☆
()

Он намекал уже с год как.

Cryptography: Hashing • encryption • key derivation • TLS • etc

Ну ять опять. Языки с всем таким потрясным интеропом с C, хватит писать свою криптографию!!!

t184256 ★★★★★
()
Ответ на: комментарий от FedyaPryanichkov

Это тяжело сделать нормально, ибо адекватная версия должна быть выглядеть как i++, но работать как ++i. А логика работы постфиксной версии из C - это что-то из области, когда байтолюбство повредило разум. Но сишники своей шизой в различении этих версий испортили идею. Теперь проше выбросить такой оператор.

На мой взгляд всё просто. Если обозначить F(i) некое выражение с вхождением i, то

F(i++);
  должно быть эквивалентно
F(i);
i++;
  а
F(++i);
  должно быть эквивалентно
++i;
F(i);

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

Psilocybe ★★★★
()
Ответ на: комментарий от uin

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

Ну и обычный (сишный) массив так ясное дело так не итерируется, только объекты vector array map

Это недочет плюсов. Сишный массив с заранее известным размером вполне можно было бы и иттерировать.

Psilocybe ★★★★
()
Ответ на: комментарий от Psilocybe

Это недочет плюсов. Сишный массив с заранее известным размером вполне можно было бы и иттерировать.

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

Siborgium ★★★★★
()
Ответ на: комментарий от X512

Исходя из того, что я вычитал (страница 32) и из твоей ссылки на StdLoader вырисовывается картина, что из модуля грузятся только смещения, а не текстовые символы, как в DLL/SO. То есть, компилятор уже знает смещения, он их подставляет в получаемый модуль. Для того, чтобы узнать эти смещения, ему нужно описание интерфейса существующего модуля. Соответственно, такая организация не равнозначна DLL/SO, которые представляют по-настоящему динамическое связывание, то есть, позволяют извне кинуть другую версию библиотеки в систему, и система продолжит работать без какой-либо перекомпиляции. Такой подход нужен, когда программы компилируешь не ты, то есть, closed-source софт. Если же софт open source, то ты можешь безо всяких модулей тупо скомпилировать всё в один блоб, а потом при необходимости делать инкрементальную компиляцию — зачем тут модули?

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

byko3y ★★★★
()
Ответ на: комментарий от X512

и в качестве языка взять С, добавить туда чего не хватает и жить спокойно ещё лет 50?

Уже есть: C++.

А еще есть D, Objective-C. С крестами получилось весьма посредственно, имхо. https://habr.com/ru/post/497114/

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от byko3y

Исходя из того, что я вычитал (страница 32) и из твоей ссылки на StdLoader вырисовывается картина, что из модуля грузятся только смещения, а не текстовые символы, как в DLL/SO.

Нет, там производится подстановка адресов импортированных по имени символов в места их использования также как в ELF с -fno-pic. Для импортированных модулей с другими адресами символов сохраняется бинарная совместимость. Собственно процесс чтения таблицы импорта и релокации происходит здесь. Первый цикл идёт по списку импортированных модулей, второй цикл — по импортированным символам из модуля. Бинарный поиск символа в модуле по имени делает Kernel.ThisObject(imp.mod, name), imp.mod это заголовок загруженного модуля в памяти, содержащий указатель на таблицу экспорта. Далее делается вызов Fixup, который читает список релокаций и осуществляет запись адреса символа с возможным смещением в сегменты модуля. Используется сжатый формат релокаций: для одного и того же символа старое значение по адресу релокации указывает на следующий адрес релокации так что релокациии могут вообще не практически не занимать дополнительного места и храниться там, куда должны быть записаны адреса импортированных символов.

Если же софт open source, то ты можешь безо всяких модулей тупо скомпилировать всё в один блоб, а потом при необходимости делать инкрементальную компиляцию — зачем тут модули?

В Оберон системах можно динамически загружать и выгружать модули в рабочей системе без перезагрузки. Сделали изменения в коде модуля, скомпилировали, перезагрузили только этот модуль и будет использоваться новая версия модуля. Также в Оберон системах можно легко вызывать экспортированные процедуры модуля из GUI (в классическом Обероне средней кнопкой мыши по Модуль.Процедура, в BlackBox по нажатию объекта «коммандер» перед командой или оборачивание команды в ссылку/кнопку/пункт меню).

скомпилировать всё в один блоб

Ещё динамическая загрузка работает намного быстрее, чем статическая линковка. Компиляция и перезагрузка модуля занимает меньше пол секунды. Можно часто править и перезагружать модуль, будет сразу виден результат. Очень удобно по сравнению с C/C++.

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

Есть система рабочих директорий по типу virtualenv Питона. Можно использовать номер версии в имени модуля (например Display, Display2, Display3 из ETH Oberon), одинаковые символы в разных модулях не вызывают коллизий.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 2)
Ответ на: комментарий от SZT

А еще есть D

Полумёртв.

Objective-C

В процессе закапывания в пользу Swift с несовместимым с Си синтаксисом.

X512 ★★★★★
()
Ответ на: комментарий от X512

Нет, там производится подстановка адресов импортированных по имени символов в места их использования также как в ELF
Бинарный поиск символа в модуле по имени делает Kernel.ThisObject(imp.mod, name), imp.mod это заголовок загруженного модуля в памяти, содержащий указатель на таблицу экспорта

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

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

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

byko3y ★★★★
()
Ответ на: комментарий от byko3y

квадратичную сложность на бинарный поиск в M модулях с N символов в каждом

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

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

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

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от X512

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

А линь не использует релокаций, машинный код 1 к 1 отображается в память из файла.

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

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

И как ты предлагаешь новому модулю работать с переменными старого модуля?

byko3y ★★★★
()
Ответ на: комментарий от byko3y

А линь не использует релокаций, машинный код 1 к 1 отображается в память из файла.

Использует: запись адресов импортированных символов в GOT — это тоже релокация, для неё используется та же таблица релокации.

У одного Firefox сотни тысяч модулей, так что при таком подходе сотню тысяч набить легко — именно потому мелкие модули линкуют в крупные модули

Для таких крупных приложений это оправдано. Но есть много не таких больших приложений где динамическая линковка с релокациями будет быстро работать. Можно также сделать кэш на диске с релоцированными модулями и загружать их по тому же виртуальному адресу. 64 битного адресного пространства должно хватить чтобы зарезервировать виртуальные адреса под все модули в системе. Так ещё можно экономить таблицу страниц виртуальной памяти в ядре используя те же части таблиц для одного модуля в разных процессах.

И как ты предлагаешь новому модулю работать с переменными старого модуля?

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

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от X512

Использует: запись адресов импортированных символов в GOT — это тоже релокация, для неё используется та же таблица релокации

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

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

В винде основные системные либы (ntdll, kernel32, kernelbase, user32, gdi32) динамически линкуются. В линуксовых дистрах в штатных пакетах тоже по возможности предпочитают динамическую линковку для экономии памяти. Но лишняя линковка — это лишнее время загрузки, потому по возможности ее делают на этапе компиляции.

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

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

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Но лишняя линковка — это лишнее время загрузки, потому по возможности ее делают на этапе компиляции.

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

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

Ничего, в других системах с модулями (C/C++, Java/C#, Python, Go, Rust и т.д.) так тоже можно. Модули в одном адресном пространстве могут использовать экспортированные символы других модулей. Компилятор Оберона проверяет так чтобы модуль не использовал приватные символы других модулей.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от imatveev13

ЧЯДНТ?

Путаешь снисхождение компилятора к слабоумным мамкиным пограмистам с божьим даром.

https://godbolt.org/z/xdchdW

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

uin ★★★
()
Ответ на: комментарий от SR_team

Хех а вот так тоже не работает

#include <vector>
#include <iostream>

auto print_args(char line[127]) -> int {
    for (auto ch : line)
        std::cout << ch;
    return 127;
}

int main(int argc, char *argv[]) {
    std::vector<char> str;
    for (int i = 0; i < argc; i++) {
        for (int c = 0; argv[i][c]; c++)
            str.push_back(argv[i][c]);
        str.push_back('\n');
    }
    return print_args(&str[0]);
}
значит там компилятор тупо цикл заменил на линейный код.

uin ★★★
()
Последнее исправление: uin (всего исправлений: 1)
Ответ на: комментарий от byko3y

Но лишняя линковка — это лишнее время загрузки, потому по возможности ее делают на этапе компиляции.

Для Оберона можно сделать мультимодули, то есть когда в одном бинарнике несколько логических модулей с сохранёнными заголовками так чтобы при загрузке мультимодуля, рантаймом были видны отдельные модули мультимодуля. Сейчас такое есть только для линковки нескольких модулей Оберона в один ELF/PE.

X512 ★★★★★
()
Ответ на: комментарий от ixrws

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

Есть такой, nim называется.

shimon ★★★★★
()
Ответ на: комментарий от X512

а еще если что-то из этого константное или указывает на константное…

cvs-255 ★★★★★
()
Ответ на: комментарий от YogSagot

С++ уже умеет шаблоны с реализацией тела функций не в заголовочных файлах?

cvs-255 ★★★★★
()
Последнее исправление: cvs-255 (всего исправлений: 1)

Снова этот наркоман выходит на связь.

paran0id ★★★★★
()
Ответ на: комментарий от cvs-255

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

vaddd ★☆
()
Ответ на: комментарий от uin

значит там компилятор тупо цикл заменил на линейный код.

Нет, там все ещё не известен размер, char line[127] в объявлении функции это тоже самое, что и char *line

SR_team ★★★★★
()
Ответ на: комментарий от cvs-255

Кстати, если PE формат лучше чем ELF, то почему его не используют в linux?

Как минимум по идеологическим причинам: «это же формам винды!». Также в PE нет встроенных релокаций по произвольному адресу, но MinGW реализует свой механизм релокаций. Это сейчас не так актуально, т.к. во многих дистрибутивах используют ‘-fpic’ и импортированные символы в итоге записываются в таблицу GOT или IAT. С PE есть ещё трудность что экспортированные символы надо явно объявлять, но опять же в Линуксе с ELF уже идут по этому же пути и некоторые пакеты (например Mesa3d) собираются с -fvisibility=hidden.

Я пробовал сделать компиляцию и запуск PE модулей в Haiku и совместное использование PE и ELF. Удалось чтобы что-то работало, но столкнулся с мелкими несовместимостями ABI. Во первых MinGW почему-то передаёт this в регистре ECX, хотя используется Itanium C++ ABI. В компиляции в ELF this передаётся через стек. Во вторых в ELF для методов возвращающих структуры используется смешанное соглашение вызовов: аргументы освобождаются вызывающим, а возвращаемая структура вызываемым. В MinGW всё освобождается вызывающим. Первую проблему а смог починить в исходниках Clang, а вторую так и не смог найти где надо чинить. В результате работает только код, не возвращающий структуры. Если вернуть структуру, то будет испорчен стек.

Я экспериментировал с 32 битами, возможно в 64 битах таких проблем нет.

Кстати в BeOS (предшественнике Haiku) одно время использовался формат PE для платформы x86, но потом перешли на ELF, видимо из-за лучшей доступности компилятора (GCC). В PE использовали Microsoft C++ ABI, но свой формат ресурсов и исключений.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 5)
Ответ на: комментарий от SR_team

char line[127] в объявлении функции это тоже самое, что и char *line

Не совсем, sizeof(line) будет разное возвращать.

X512 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.