LINUX.ORG.RU

Убийца ли C язык C3?

 , ,


3

8

В честь сегодняшнего пре-релиза (0.2.4).

C3 (GitHub) - очередной «убийца» C на базе LLVM. Потихоньку разрабатывается шведским программистом (одна штука).

Ключевые особенности:

  • компилятор написан на C
  • поддержка LLVM 12-15 (насколько мне известно, ни один из конкурентов этого не может (привет, Odin, Zig и т.д и т.п.))
  • полная C-ABI совместимость
  • модули - нет хидерам!
  • дженерики
  • макросы, но не как в C
  • слайсы
  • контракты
  • compile time and runtime reflection (плохопереводимая игра слов)
  • SIMD «из коробки»
  • и многое другое!

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

macro int factorial($n)
{
        $if ($n == 0):
                return 1;
        $else:
                return $n * factorial($n - 1);
        $endif;
}

extern fn void printf(char *fmt, ...);

fn void main()
{
        int x = factorial(12);
        printf("12! = %d\n", x);
}
★★★★★

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

Ответ на: комментарий от thegoldone

Возможно, будет новая команда c3c lsp. Один энтузиаст пытается это добавить.

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

Ничего плохого не случится.

Тогда зачем существуют разные s, p, c? Был бы один {}, как в некоторых языках: print("value: {}", value).

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

Например, %s позволяет отобразить все элементы массива/вектора.

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

Я не очень понимаю. Есть пространство имён. И там, допустим,

stdio.printf("hey")
stdio.puts("hoy")

Ну или вложенность

one.nested.one_another.puts("pew")

И во время синтаксического разбора первое имя и пространство имён всё решают.

thegoldone
()

Ну и всякие сишные закидоны, типа i++, ++i, --i, i--, a = i-- – ну это прошлый век. Скорее вредные конструкции, чем стоящие.

thegoldone
()
Ответ на: комментарий от thegoldone
Again, ambiguity in the grammar.
So here's the trick in keeping the grammar just one lookahead:
1. If a lower case ident is found, then look at the next token, if this token is '::' then this is a path, parse until the last '::' is found
2. Otherwise this is a token without a path.
And this matters in cases like:
a.b.Foo a = x;
Another problem is the obvious ambiguity in the overloaded .
Imagine this:
import std.file;
...
File* file = ...
file.some_global = x;
Here the use of file is shadowing the import
It is not clear whether file.some_global was intended to access a global in std.file or a field in File* file
With :: this becomes unambiguous:
file::some_global = x;
file.some_global = x;
ambiguities resolved.
dataman ★★★★★
() автор топика
Ответ на: комментарий от thegoldone

Ну там автор как раз модули при парсинге различает по токену ‘::’. Если делать по точке, будет только одно глобальное пространство имён.

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

Это очень удобные «закидоны».

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

Да нифига. Можно держать грамматику LL(1), но сделать дополнительный проход (для семантики он всё равно будет).

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

Ну так это ложная проблема. Глобальное пространство имён перекрывается локальным, обычное дело. Ну да ладно, войны ради этого я устраивать не стану.

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

Для начала я ему предложил использовать одиночное двоеточие. Он пока не ответил. Stay tuned! :)

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

В чём принципиальная разница между структурой и модулем с точки зрения грамматики? Почему в Обероне, очень минималистичном языке, такой проблемы нет?

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

Here the use of file is shadowing the import

Поэтому модули надо называть с большой буквы:

MODULE ObxHello1;
	IMPORT Views, TextModels, TextMappers, TextViews;

	PROCEDURE Do*;
		VAR t: TextModels.Model; f: TextMappers.Formatter; v: TextViews.View;
	BEGIN
		t := TextModels.dir.New();
		f.ConnectTo(t);
		f.WriteString("Hello World"); f.WriteLn;
		v := TextViews.dir.New(t);
		Views.OpenView(v)
	END Do;

END ObxHello1.

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

Ну вот возьмём Zig: CodePoint.zig

const std = @import("std");
const unicode = std.unicode;

bytes: []const u8,
offset: usize,
scalar: u21,

const CodePoint = @This();
...

На мой взгляд, это ужасно.

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

Ну вот возьмём Zig: CodePoint.zig

Я вообще не понимаю что тут происходит. Предлагаю ещё раз обратить внимание на Оберон, там всё сразу понятно.

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

Модули str.c3 и string.c3 находятся в зайчаточном состоянии, пока не до них. :)

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

Это как раз пример того, как в Zig «волшебным» словом @This() модуль превратился в структуру.

Предлагаю ещё раз обратить внимание на Оберон

Да я обратил, конечно! Но автор строг к изменению грамматики. Например, я так и не переубедил его, что имя типа не обязано начинаться с заглавной буквы и быть длиннее двух символов, или что имена членов enum не должны быть КАПИТАЛЬНЫМИ, etc.

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

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

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

Нет, goto нет. Это для switch. Самую актуальную информацию можно получить так:

$ c3c <switch>

  --list-attributes      - List all attributes.
  --list-builtins        - List all builtins.
  --list-keywords        - List all keywords.
  --list-operators       - List all operators.
  --list-precedence      - List operator precedence order.
  --list-type-properties - List all type properties.
  --list-targets         - List all architectures the compiler supports.
dataman ★★★★★
() автор топика
Ответ на: комментарий от thegoldone

Как раз таки это век будущий. Как прошлым веком может быть что-то более совершенное чем дефолтное?

Вредные чем? Вредные почему?

right_security
()

Сишку столько раз «убивали», а она по прежнему жива

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

Вангую, что будет, как с D. Реально интересные фичи заберут в C++, после чего нужность самого языка окажется под вопросом (модули вот уже забрали).

Это 4.2 лютое. d это язык времён 0x и именно туда тащили всё из С++, а не наоборот. Просто в C++11 притащили не всё, а очень малую часть. В d же тащили всё, без разбору. Что его и погубило.

А никаких «киллер-фичей» Д в цпп до сих пор нет.

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

Модули в цпп это просто семантические инклюды. В инклюдах нет своего неймспейса, нет static/extern как для tu. Сравнение этого с какими-то иными языками всегда подмена понятий.

Я вот не считаю, но и крестовый поход против си из-за этого устраивать не буду. «Не жили богато, нечего и начинать».

Я можно аргументацию? Да и в целом, почему ты за «Не жили богато, нечего и начинать», а ссылаешься на этот «подход» в контексте недостатков.

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

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

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

грамматика должна быть класса LL1.

Если ты студент начальных курсов - да.

сишная таковой не является.

И правильно. Я тебе больше скажу, у крестов вообще нет грамматики. Она слишком сложная чтобы её даже формализовать, не что в ll1. Это никто не делает.

следуя этому нехитрому знанию про LL1 и пишут всякие fun, var, type, class и тепе.

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

Если ты за ll1, то почему пишешь не на ll1? Зачем тебе подлый русский - он не ll1. Любой нативный язык такой. Ах да, это другое. Как я мог забыть.

Кстати, как можно вообще не мочь и знать? Это же противоречие. Если ты не можешь - ты будешь писать fun. Если можешь - зачем писать то, что можно не писать? Почему ты, допустим, не пишешь это в лямбдах, если мы возьмём какой-нибудь раст/js.

Поэтому перед последователями ll1 не стоит вообще какого-либо выбор писать/не писать. А вот у сишников стоит, потому что они могут как писать так и не писать. И они выбрали. Но вот свидетельств того что выбирал ты - они есть? Я их не вижу - ты не показал. Покажи.

right_security
()
Ответ на: комментарий от fluorite

Автор пишет рекурсивный спуск

Тут уже грамматика мимо, если автор пишет рекурсивный спуск.

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

Нет, ты вводишь в разбор понятие контекста - это нарушает принцип. Символы и прочая чушь из википедии - ты не правильно её понимаешь.

Контексто-свободная грамматика она на то и свободная, а ты засунул в неё контекст.

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

Но если ты попытаешься формализовать свой разбор в грамматику, то она уже не будет никакой ll(1). Она будет ll(ctx, 1), если попроще.

right_security
()
Ответ на: комментарий от alysnix

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

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

right_security
()
Ответ на: комментарий от MOPKOBKA

Ты делаешь ту же ошибку, что и те же раст-агитаторы. Да много какие агитаторы.

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

На уровне языка есть семантика, т.е. понимает ли твой язык этот компилтайм. Проверить в случае с си это просто - попробуй сделать int x = factorial(12); не в main, а глобально.

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

Как раз таки это век будущий. Как прошлым веком может быть что-то более совершенное чем дефолтное?

Вредные чем? Вредные почему?

Читается код много больше раз, чем пишется. И чем читаемость кода

for (;;) {
   array[--some];
}

лучше чем

for (;;) {
    array[some];
    some -= 1;
}

?

Исходя из того, что читающему интересно что происходит в этом коде.

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

Нет, она не работает быстрее. Не мочь в грамматику и в парсеры не означает, что они будут быстрее работать.

Ну и парсинг в процессе компиляции ничего не стоит. Особенно если мы говорим о каких-нибудь инкрементальных/ленивых парсерах.

Я тебе даже больше скажу - чем больше контекста тем быстрее парсинг. И от этого контекста ты никуда не уйдёшь. Языки иначе не работают.

А сам миф «быстрее» обусловлен тем, что для примитивных грамматик(а именно такие влезают в контексто-свободные особенно 1) можно создать всякие генераторы, где после студенты будут сравнивать результаты работы генератора с самописной лапшой.

Т.е. это даже не сравнение кода, а сравнение кода неофитов не обученных с кодом тех, кто понимает. О каком-то сравнении с более сложными грамматиками и речи не идёт.

Да и в целом для реальных языков формализацией никто не занимается. Формализация может только в крайне примитивные вещи. Точно так же как для реальных сложных языков никто не использует всякие генераторы.

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

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

fluorite ★★★★★
()
Ответ на: удаленный комментарий

Лол. И чем же грамматика мешает написать такой парсер?

Тем, что парсер такой пишут тогда, когда грамматика не осилила. Т.е. когда грамматики нет.

Ну ты и дебилушка. Вот в пользовательском коде объявляется переменная foo. В какой-то пользовательской функции в неё записывают значение, а в какой-то читают. Покажи, как без использования чего-то вроде std::unordered_map<std::string, llvm::Value*> сгенерировать машкод?

Зачем ты навязываешь мне невежество? Какой-то машинкод, какие-то значения. Ты не понимаешь тему. Да ладно не понимаешь - зачем ты переключился на переменные, если выше речь шла о type/value.

С чего ты взял, что грамматика c3 контекстно-свободная?

Причём тут c3? Речь шла о ll1 - она контексто-свободная по определению.

right_security
()
Ответ на: комментарий от fluorite

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

Опять же ты повторяешь лозунги не понимая их смысла. И да - не поэтому не используются. Ну и иди мне покажи это генератор для C++.

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

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

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

а не потому что «конечные автоматы с магазинной памятью» сложно генерить.

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

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

Тем, что парсер такой пишут тогда, когда грамматика не осилила

Ты ещё предложи приоритеты операций для выражений через грамматику оформлять.

Ты не понимаешь тему.

Ты же понимаешь, правильно? Вот расскажи - зачем и почему. Аргументируй.

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

Диагностики берутся из контекста, т.е. руками написанные парсеры не являются контексто-свободными.

Что за бред вообще.

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

Читается код много больше раз, чем пишется. И чем читаемость кода

Нет. Это тебе нужно рассказывать «чем она хуже», а не мне. Ты утверждал это, а не я.

Но я даже сделаю скидку и объясню тебе.

Очень часто можно услышать, что компактность/выразительно нужна для «пишется», но на самом деле нет. Абсолютно без разницы с ТЗ писать на то какой вариант использовать. Это в принципе максимально очевидно и в доказательствах не нуждается.

А вот когда мы читаем - мы хотим получить ту самую выразительность/компактность. Чтобы видеть больше, видеть меньше мусора.

Точно так же как написать мусорный длинный текст просто. А написать хороший ёмкий текст сложно. Хоть и писать меньше.

И что мы видим в твоём примере? Мы видим 50% места занято мусором. Т.е. если эта функция будет на один экран, то первый вариант я смогу прочитать сразу. А вариант два мне нужно будет скроллить.

Скролл самое худшее, что может произойти чтении кода. Поэтому чем меньше мусора. Чем меньше бойлерплейта - тем лучше.

Исходя из того, что читающему интересно что происходит в этом коде.

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

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

Это 2 использования вместо одного. Между ними может быть много кода. Это, опять же, скрол/потеря контекста.

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