LINUX.ORG.RU

Вышел Golang 1.17

 


1

3

Как всегда, релиз следует обещанию совместимости с Go 1.x. А значит что все существующие программы так же будут собираться Golang 1.17.

Изменения в языке

Указатель на массив

  • Преобразование из слайса []T в указатель на массив *[N]T, конструкцией вида go var array = (*[50]byte)(slice) Вызывает run-time panic при выходе за границы. Подробно.

unsafe

  1. unsafe.Add(ptr, len) = unsafe.Pointer(uintptr(ptr) + uintptr(len))
  2. unsafe.Slice, превращает указатель *T в слайс, unsafe.Slice(ptr, len) -> []T
Инструменты

Различные изменения в инструментах, включая

  • Сокращённый граф модулей для go 1.17 модулей.
  • Ленивая загрузка модулей
  • Отдельные блоки require в go.mod для косвенных зависимостей.
  • Добавлена поддержка комментария // Deprecated: в go.mod.
  • Удалена поддержка флага -insecure в go get -insecure
  • Если в go.mod отсутствует директива go, то версия принимается за go 1.11, а не за текущую. А для зависимостей с тем же изъяном за go 1.16 (о-оу).
  • Для модулей go1.17 команда go mod vendor теперь создаёт файл vendor/modules.txt и не включает go.mod и go.sum зависимостей.
  • Подавление запроса пароля при загрузке по SSH. Можно настроить.
  • Для обновления go.sum теперь стоит вызывать go mod download all как то было в go1.15.
  • Добавлен магический комментарий //go:build lines вместо // +build lines что бы [это ни значило]https://golang.org/design/draft-gobuild).
  • go run теперь позволяет запускать конеретную версию пакета, по типу go run example.com/cmd@v1.0.0
  • go vet бросает новые предупреждения для
    • //go:build and // +build lines
    • при подписке signal.Notify на канал без буфера
    • когда методы Is, As и Unwrap отличны от описанных в errors, но используются пакетом errors
  • cover теперь быстрее работает, но заметно только на огромных проектах
Компилятор
  • Аргументы передаются через регистры, а не стек. Что даёт ускорение около 5%, и снижение размера файла около 2%. Это только для 64-битных Linux, MacOS и Windows (linux/amd64, darwin/amd64, windows/amd64). Это изменения не касается безопасного кода, в основном относится к его unsafe части.
  • Так же улчшен формат runtime.Stack.
  • Функции содержащие замыкания теперь тоже могут быть встроены (inlined).

Компоновщик (linker)

  • Если используется внешний компоновщик, то опция -I передаётя ему.
Основные библиотеки

Cgo

  • Пакет runtime/cgo добавляет поддержку для передачи значений между Go и C. Посмотрите на runtime/cgo.Handle.

Разбор URL-query

  • Ранее, пакеты net/url and net/http принимали ; (точку с запятой) как разделитель наряду с &. Теперь это не так. И даже ошибка летит в лог, если встретится точка с запятой. Значения с ней игнорируются. Изменить поведение обратно для net/http можно с помощью [AllowQuerySemicolons]https://pkg.go.dev/net/http@master#AllowQuerySemicolons), но это сделано для безопсности.

И так далее включая небольшие изменения в библиотеках. Из которых, может стоит, отметить методы

  • time.Time.IsDST – летнее время
  • time.Time.UnixMilli и аналогичный ему UnixMicro для тех, кто не умеет делить сам
  • net.IP.IsPrivate
  • Методы Swap и CompareAndSwap для atomic.Value.
  • Для тестов добавлен флаг -shuffle для запуска тестов в хаотичном порядке.
  • Так же в тестах теперь есть методы T.Setenv (и для B тоже). Которые выставляют переменную на время теста или бенчмарка.

Текст новости исправлен и переработан @Shaman007 и другими корректорами

>>> Подробности



Проверено: Shaman007 ()

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

Java — очень хорошая промышленная платформа для разработки софта. Одна только обратная совместимость очень дорогого стоит.

Платформа хорошая, но далеко не идеальная. Вопросам интеропа с нэтивом там не занимались с момента появления JNI-костыля. Который изначально и планировался как костыль.

Сейчас этим добротно озаботились, и появился Graal. Годная вещь, я юзал (JS <- Java <- JNI <- C++), понравилось. Посмотрим, куда оно вырулит.

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

Теперь ты - корректор

То есть пользователя могут назначать корректором без специальной заявки (например, в виде письма на мыло maxcom'у)? Спрашиваю, т. к. реально не в курсе.

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

То есть пользователя могут назначать корректором без специальной заявки (например, в виде письма на мыло maxcom'у)?

Ты это, того. Поаккуратней там. Так и корректором стать недолго.

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

Он на это и рассчитывал, я думаю. Стать корректором.

Нахер нужно.

проще исправить, чем возмущаться

Давно бы сделали поддержку патч/мерж/пул-реквестов к новостям. Не пришлось бы выдавать какие-то «особые права корректора», а участник с правами просто ревьюил и принимал бы фиксы.

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

Мономорфные дженерики — это далеко не только «подставь вот сюда вот это тип».

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

Это, в первую очередь, вывод типов + специализация кода.

Это уже следствие. И при использовании кодогенератора просто не нужно. Т.е. необходимость в выводе типов и специализации вызвана именно использованием шаблонов (то, что ты называешь мономорфными дженериками), также как использование дженериков (полиморфные дженерики в твоей классификации) требует дополнительного кода в JVM для оптимизации в рантайме.

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

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

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

Я вижу, что тут надо пояснить. Я тут под выводом типов подразумеваю и (полное по Тьюрингу) раскрытие шаблонов в том числе. auto — лишь частный случай этой процедуры.

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

Ну вот ты сам ответил)) Проблема TMP в C++ в том, что оно изначально под метапрограммирование не делалось, и стало использоваться не по назначению. TMP — трясина Тьюринга, и что-то большое на нем написать получается слишком трудоемко. Кроме того, на нем трудно делать метапрограммирование уровня AST.

Так вот, вещи, которые ты называешь дополняющими друг-друга — это метапрограммирование уровня типов (TMP C++) и метапрограммирование уровня AST (процедурные макросы). И таки да, метапрограммирование в С++ было бы на много проще, если был кодогенератор уровня AST, который мог бы дергать вывод типов (type traits, инстанцирование шаблонв) при необходимости.

У меня в проекте есть такой кодогенератор на основе библиотек Clang и Питона. Его возможности пока скромные — процессор аннотаций/анализатор AST, но он может делать вывод типов и интегрироваться с имеющимися библиотеками шаблонных метапрограмм. TMP при этом будет становится на много проще (чем без кодогенератора), а python можно легко отлаживать в процессе.

Когда Мемория созреет, её кодогенератор можно будет реюзать в других проектах. В последствии я перенесу эти наработки в Jenny Platform. Там вместо Питона будут метафункции на С++, вызываемые компилятором через JIT.

И вот такие вещи я хотел бы видеть в Go, но оно там, как есть, концептуально еще лет на 10-15 отстает от современного уровня. В Go даже аннотаций нем. Там даже непонятно, как метаданные с кодом связывать, не привлекая внешние файлы.

Я боюсь, что дженерики в Go навсегда останутся «нежеланным ребенком». Они всё очень сильно усложняют, а автор хотел бы видеть свой язык простым. Ради этого он его и делал.

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

Проблема TMP в C++ в том, что оно изначально под метапрограммирование не делалось, и стало использоваться не по назначению.

Ну что есть, то есть. С++ был первый, не на кого было ориентироваться. А вот D учел ошибки плюсов, шаблонное метапрограммирование там намного удобнее (есть не только более мощный static if, но и static foreach) и очень развита рефлексия времени компиляции (можно пробежаться по всем членам агрегата, включая специальные, и получить их характеристики). Кстати, std::range писалась именно по мотивам D, вот оригинальная статья, которой вдохновлялся Erich Niebler. Нет AST макросов, правда, но это принципиальная позиция автора языка - он считает AST макросы очень мощной техникой, которая приводит к балканизации экосистемы. Потому что с помощью AST макросов можно создавать по сути диалекты языка, естественно не совместимые с собой со всеми вытекающими последствиями. Вместо них в D строковые миксины - по возможностям они не сильно уступают AST макросам, если вообще уступают, но они неудобные - именно поэтому их оставили в языке, что дескать люди будут писать только реально нужные вещи на них, где по другому уже совсем никак, а просто так на них писать не будут. Аннотации в D тоже есть, user defined attributes, штука, конечно, полезная. И совместимость 100% с сишным кодом и уже не 100% с плюсовым кодом, но включая плюсовые шаблоны. На D можно написать все вещи, что ты делаешь (снимаю шляпу, кстати, пользуясь случаем, впечатляет), причем в рамках стандарта языка - а это иногда очень критично, в крупные проекты затащить зависимость то бывает не просто, да даже версию обновить, а тут тулчейн нестандартный - это может быть сложно, несмотря на все достоинства.

Я боюсь, что дженерики в Go навсегда останутся «нежеланным ребенком». Они всё очень сильно усложняют, а автор хотел бы видеть свой язык простым. Ради этого он его и делал.

И я думаю, что именно простота языка и позволила ему взлететь. А если туда начнут пихать все подряд, язык потеряет свою фишку. Я бы на месте Майка очень много подумал, прежде чем усложнять язык. Уже С++ есть, хороший, но временами просто противоречивый, бывает, что в проекте живет и старый, и новый код и они выглядят, как будто это разные языки, ощущение дисгармонии возникает. И все это именно из-за впихивания новых фич при сохранении совместимости со старыми. Триграфы только вот выпилили пару тройку лет назад. Неужели его опыт ничему не учит?

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

Ок, годные аргументы. Разберу по сути.

Я на D смотрел давно, с самого начала. Как язык, он мне нравится/нравился, но инфраструктура вокруг него откровенно слабая. Метапрограммирование в нем было заметно мощнее, чем в С++. Но последний сейчас тоже развивается. Я Jenny Platform поднимал над пилотной имплементацией Reflection TS, которая умеет вот это вот всё (рефлексия + квотинг). Но проблема следующая...

У языка должен быть какой-то драйв развития. Есть языки академические, целью которых является некая «математическая красота». Есть языки, типа Python, целью которых является низкий входной порог в программирование. Сейчас, например, много людей приходит в программирование прямо с улицы, вот Python и прет. У C++ это zero cost abstractions + close to metal.

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

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

Это означает, что метапрограммы должны иметь возможность читать и писать файлы, ходить в сеть и в БД, запускать треды. Если мне нужно применить constraint solver или theorem prover, я должен иметь возможность это сделать. Ни текущий Reflection TS, ни средства D не позволяют мне этого сделать. Т.е. это всё хорошо, но совершенно недостаточно для, например, той же Мемории.

До сих пор для масштабного метапрограммирования просто не было хороших задач. Генерить бойлерплейт для ORM или байндинги к сериализации — это не впечатляет. Другое дело, когда, например, метапрограммы создают полный стек хранения и обработки данных, оптимизированный под железо и задачу. Меморию как раз и можно использовать как практический драйвер потребности в продвинутых техниках метапрограммирования. И, как стандартный фича-тест для языков, которые декларируют возможности метапрограммирования :).

Что касается framework lock-in. Jenny Platform — это, действительно, он. Codegen в Мемории — нет. Он не инвазивный, так как может только читать AST, а не создавать. На выходе там обычные исходники и другие бинарные артефакты, когда/если надо.

Короче, чтобы было понятнее. Я не обвиняю дизайнеров языков в некомпетентности. Они находятся в своей песочнице применения языка, в которой и живут. D, несмотря на то, что он достаточно мощный, не решает проблем метапрограммирования в C++. И чтобы мотивировать языки к качественному развитию в этом направлении, нужны хорошие задачи. Вот я одну такую задачу и даю.

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

Ну, не только это, а еще и слово Google в названии :) Вокруг полным-полно простых языков, но они не получают такого пиара, как golang.

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

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

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

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

Пусть с опозданием, но отвечу все же.

D мощнее плюсов и всегда им будет просто по той причине, что плюсы тянут с собой кучу легаси - в этом и сила с++ и его слабость. В результате в цпп есть обычный код, и есть шаблонный, а сейчас еще метаклассы появятся - и будет уже три подмножества плюсов. В D все намного более органично смотрится. Там нет нужды в `constexpr`, `static if` не вводит scope, есть `static foreach` - это только часть из того, что делает разработку на D намного продуктивнее чем в c++, есть еще намного более быстрая компиляция. Единственный плюс у плюсов тут - дишный фронтэнд (а он один для всех трех компиляторов - и это плюс) потребляет много памяти by design, т.к. изначально ориентирован на одноразовый запуск и память просто не освобождал по началу вообще - за счет чего и скорость компиляции поднималась, сейчас работы ведутся в этом направлении. Также навскидку в D не нужно использовать typename, в качестве аргументов можно передавать не только целые, но и строки и другие типы, специализацию делать намного удобнее. Вход в метапрограммирование на D намного легче чем в плюсах. Да, у цпп экосистема на несколько порядков больше. Но в этом же и минус. Что касается дата-платформы - так тут у плюсов уже нет никакой экосистемы, ее еще только нужно создавать. И тут у D как раз преимущества - нет отягощающего легаси.

Про чтение и запись файлов, работу с сетью и запуск тредов - в сообществе D придерживаются мнения, что только чтение файлов должно быть доступно в CTFE (и оно уже доступно), иначе результат компиляции просто будет зависеть от фазы луны и гарантировать воспроизводимость сборки уже будет сложнее. Но думаю, что тут нужно побольше поиграться, возможно позднее ослабят это ограничение.

Также не соглашусь, что D не решает проблемы метапрограммирования в С++ - плюсовое метапрограммирование лишь подмножество дишного по моему мнению.

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

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

Согласен, но мне кажется это естественный этап развития. Посмотрим, как он пройдет.

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

С этим трудно поспорить, это грамотное решение. Я не призываю ни в коем случае переписывать меморию на D, это было бы странно. А вот новые проекты - почему бы и нет.

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

С этим трудно поспорить, это грамотное решение. Я не призываю ни в коем случае переписывать меморию на D, это было бы странно. А вот новые проекты - почему бы и нет.

С D такая же ситуация для меня, какая в свое время была с Rust, когда я с ним только знакомился. Да, язык прикольный. Да есть макросы (очень хотелось для eDSL). Да, есть линейные типы и всё такое. Но совершенно нет библиотек. Их нет и сейчас, несмотря на 40К+ крейтов с crates.io.

Ну не побегут все переписывать уже написанный софт с C++ на Rust, как не стали переписывать в своё время на Java. И на D не побегут переписывать, потому что преимущества языка этого не стоят. Гораздо проще добавить в С++ те же метафункции и получить то, что надо, чем переходить на совсем другой язык и при этом терять большую часть унаследованного кода. Потому что «новые проекты» обычно основаны на кодовой базе «старых».

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

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

Ну не побегут все переписывать уже написанный софт

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

Потому что «новые проекты» обычно основаны на кодовой базе «старых».

Бывает и так, но далеко не всегда.

Добавление метафункций в С++ создает еще один язык, который имеет еще меньше man power со всеми вытекающими. И добавляя новые фичи в диалект языка, вы не можете избавиться от изъянов его текущего дизайна, потому что вы вынуждены тащить все легаси. Стоит только вспомнить про «богатство» способов инициализации в плюсах и как это усложняет метапрограммирование, потому что вы должны предусмотреть все возможные варианты, ведь инициализация зависит от типа. Добавляя новые фичи в без того перегруженный дизайн языка вы его еще больше усложняете. Не факт, что после многолетнего использования своего диалекта позднее не вылезет какой-нибудь конфликт с языком - просто потому что это с++, там уже столько всего наворотили.

Еще раз, я не уговариваю именно вас переписывать ваш код, очевидно, что вы уже сделали выбор в пользу с++ и это ни хорошо, ни плохо. Я больше пишу для других, для тех кто устал бороться с какими-то моментами и хочет попробовать что-то другое, как это было у меня в свое время. Единственно, что меня на данные момент расстраивает в D - это невозможность применять его везде, где бы я хотел.

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

Ты говоришь о С++ так, будто он сам не развивается и застрял где-то на уровне С++11. Он развивается, он становится лучше. А legacy и в D появится. И будет тянуться дальше, перегружая язык.

Метафункции не создают новый язык, они создают новый диалект. Но из-за наличия раздельной компиляции применение метафункций можно ограничить периметром внутренностей библиотек. Примерно так же мы сейчас используем С++20 «внутри» библиотек и «С++14» снаружи.

Т.е. выбирать D только по соображениям его более продвинутого метапрограммирования я бы не стал. Слишком много придется потерять ради того, для чего можно и диалект в С++ сделать (ничего при этом не потеряв).

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

Ты говоришь о С++ так, будто он сам не развивается и застрял где-то на уровне С++11. Он развивается, он становится лучше.

С++ развивается, но он тащит с собой кучу легаси. Вот пример решения задачи FizzBuzz в компайл-тайме на С++:

#include <iostream>
#include <string>
#include <array>

consteval std::array<char, 5> FastToString(unsigned value) {
	constexpr unsigned another_hack = '0';
	if (value == 100) {
		return { '1','0','0', '\n', '\0'};
	}
	if (value < 10) {
		return { '0', '0', static_cast<char>(value + another_hack), '\n', '\0' };
	}
	else {
		return { '0', static_cast<char>((value - value % 10) / 10 + another_hack), static_cast<char>(value % 10 + another_hack), '\n', '\0' };
	}
}
consteval size_t ResultLength() {
	size_t result = 0;
	for (int i = 1; i <= 100; ++i) {
		switch ((i % 3 == 0) * 10 + (i % 5 == 0)) {
		case 0:
			result += sizeof("100\n");
			break;
		case 1:
			result += sizeof("fizz\n");
			break;
		case 10:
			result += sizeof("buzz\n");
			break;
		case 11:
			result += sizeof("fizzbuzz\n");
			break;
		}
	}
	return result;
}
consteval auto FizzBuzz() {
	std::string result;
	for (unsigned i = 1; i <= 100; ++i) {
		switch ((i % 3 == 0) * 10 + (i % 5 == 0)) {
		case 0:
			result += FastToString(i).data();
			break;
		case 1:
			result += "fizz\n";
			break;
		case 10:
			result += "buzz\n";
			break;
		case 11:
			result += "fizzbuzz\n";
			break;
		}
	}

	std::array<char, ResultLength()> fb{};

	for (int i = 0; auto& v : result) {
		fb[i++] = v;
	}
	return fb;
}
int main() {
	for (auto v : FizzBuzz()) {
		std::cout << v;
	}
}

взято отсюда, оно же на godbolt

А вот решение на D, естественно в компайл-тайме:

import std;

auto fizzBuzz() {
	string[] result;
	foreach (i; 1..100) {
		switch ((i % 3 == 0) * 10 + (i % 5 == 0)) {
        default:
			result ~= text(i);
			break;
		case 1:
			result ~= "fizz";
			break;
		case 10:
			result ~= "buzz";
			break;
		case 11:
			result ~= "fizzbuzz";
			break;
		}
	}
    return result;
}

void main() {
	pragma(msg, fizzBuzz);
}

оно же на godbolt

В D версии ни одного constexpr, consteval не пострадало - они были в ведены, потому что плюсы хотят сохранять совместимость и это плата. В итоге в D чтобы написать функцию для вычисления во время компиляции вам просто нужно написать обычную функцию - и все. А в плюсах вам нужно написать отдельную функцию для таких вычислений. Нужно городить огород для преобразования числа в строку - т.е. во время компиляции можно использовать заметно меньшее подмножество языка, чем во время выполнения.

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

Метафункции не создают новый язык, они создают новый диалект. Но из-за наличия раздельной компиляции применение метафункций можно ограничить периметром внутренностей библиотек. Примерно так же мы сейчас используем С++20 «внутри» библиотек и «С++14» снаружи.

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

Т.е. выбирать D только по соображениям его более продвинутого метапрограммирования я бы не стал. Слишком много придется потерять ради того, для чего можно и диалект в С++ сделать (ничего при этом не потеряв).

Ну в проекте, завязанном на метапрограммирование как раз точно стоит предпочесть D плюсам - там разница просто огромная, D намного удобнее и продуктивнее в этом плане. Более дружелюбный и человеческий, чем плюсы. Более того, в D не только более продвинутое метапрограммирование. Там например, компиляция намного быстрее. Референсный компилятор D собирается из исходников за несколько секунд(!). Полноценный компилятор с нуля (без кешей) за несколько секунд. Те же ренжи в D используются в хвост и гриву уже много лет, а в плюсах уже третья версия и то не особо популярна. И самое главное - ренжи в D можно в debug сборке спокойно использовать, просадки производительности нет такой как в плюсах. В D нет вопросов на форуме - как использовать модули. Они есть, работают из коробки и не вызывают никаких вопросов.

А диалект плюсов - да, это не другой язык, но и уже не стандарт со всеми вытекающими. И что-то мне говорит, что поддержка собстственного диалекта языка это сама по себе серьезная задача. А bus effect никто не отменял. Тут еще нужно сравнить сколько разработчиков в том же D и сколько разработчиков в собственном диалекте С++ - сравнение будет явно в пользу D.

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

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

Wow, чувак! Спасибо за труд, искренне. Ты отлично популяризуешь свой любимый язык. Таким людям, как ты, будет рад любой проект.

Я принимаю большую часть твоих аргументов в пользу D. Безусловно, если сравнивать возможности метапрограммирования в D и в C++, то первый сейчас на голову выше. Давай я тебе дам фидбек на эти возможности, как человек, профессионально занимающийся метапрограммированием. Гоферам тоже пригодится. TL;DR — возможности хорошие, но совершенно недостаточные IRL, и сами по себе погоды не делают.

Есть такая штука — programming in large, которая сделала Java тем, чем он сейчас является. Программирование в большом в Java очень хорошее. Даже слишком хорошее. Не относительно других языков, а само по себе. Оно позволяет писать и сопровождать огромные проекты. Тут не важно, что конкретные проекты на Java «заплыли жирком» сверх всякой меры. Важно то, что с Java я не боюсь очень больших кодовых баз. Код, написанный 20 лет назад, продолжает работать и сегодня без каких-либо замечаний. Это просто отличная работа инженеров, развивающих эту платформу.

Точно так же, есть проблема метапрограммирования в большом. Но на практике она до сих пор обозначена не была. Причем на столько, что языки, позиционирующие себя как языки для метапрограммирования, до сих пор обсуждают, а надо ли позволять полное множество языка в метапрограммах, включая потоки и ввод-вывод. Так уж сложилось, что практически значимых проектов, ставящих вопрос о метапрограммировании ребром, до Мемории не было (to the best of my knowledge).

Вот, возьмем к примеру, C++ TMP. Это не просто трясина Тьюринга, оно еще и не масштабируемо никак, оно еще и вычислительной способностью где-то на уровне продвинутого арифмометра.

Ну, хорошо. Сделали мы условный Zig, с полным метапрограммированием. Что дальше? Нужна хорошая интеграция метапрограмм с системой сборки. Нужны библиотеки хорошие метапрограмм. И последнее — это ведь не просто прибамбасики для генерации бойлерплейта для сериализации состояния объектов. Метапрограммы — это проект-специфичные расширения компилятора. Доказательство теорем, constraint solving? Да, надо. Нужна полноценная платформа. Её кто-то уже делает? Или мне нужно полагаться только на себя? Если только на себя, то зачем я буду создавать себе проблемы перескакиванием на другой язык?

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

И вот теперь основной вывод. Вот, например, мне нужно продвинутое метапрограммирование. И, вот, есть у меня C++ и D, и оба сильно не дотягивают, нужно всё равно делать диалект. С D легче, но я теряю накопленную кодовую базу на С++ и нишу использования языка. Что уже очень много.

Если есть шансы того, что диалект С++ будет страдать от bus factor, то шансы того, что соответствующий диалект D вообще не получит никакого интереса — просто зашкаливают. Язык-то хороший, продвинутый. Но без задач для него. В них всё дело.

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

Вот, с другой стороны. Хочу я, например, полное подмножество языка в метафункциях в С++. Прихожу я с этой хотелкой в комитет по стандартизации, а мне говорят «а зачем?». И правильно, а зачем? Какую практически важную задачу это решит? А никакой. Ну, кроме генерации бойлерплейта. Что конкретно для С++ очень важно само по себе (отстаем-с немеряно-с), но для этого метафункции не нужны. Есть куда более более простые и не интрузивные решения, типа таких, которые я сейчас в Мемории применяю (проект-специфичный кодогенератор на основе библиотек Clang и метапрограмм на Python).

Приходить в комитет по стандартизации нужно с проблемой и прототипом решения. Вот, ребята, есть такая актуальная технологическая проблема. Вот есть Мемория, как её решение. Хотите, чтобы С++ для этого класса проблем стал языком безусловного выбора? Давайте стандартизируем вот этот диалект и вот эту открытую платформу на его основе. Можно перед этим всё радикально переработать, чтобы было консистентно с другими фичами языка, что диалект сейчас не учитывает. Вот так оно работает.

Я к чему это всё? Если сообщество D готово к серьезному рывку вперед в плане поддержки метапрограммирования в большом, я готов помогать в этом направлении и актуальными практическими задачами, и кодом (на С++).

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

Не люблю слово «чувак», но за добрые слова все равно спасибо.

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

Помимо С++ TMP (template meta programming, как я понимаю) в D есть еще CTFE (compile time function execution), причем уже много лет. Естественно, полное по Тьюрингу и масштабируется и по быстродействию получше чем TMP - хотя по быстродействию и потреблению памяти есть нарекания, ведется работа над новым движком CTFE, но пока результатов нет.

Условный Zig в контексте метапрограммирования звучит немного непонятно, т.к. в Zig метапрограммирования нет вообще, насколько я знаю.

Непонятно про интеграцию метапрограмм с системой сборки - в D метапрограмма же это просто код, который интерпретируется (именно интерпретируется) в процессе компиляции и система сборки здесь на другом уровне вообще. Уточни, почему нужна эта интеграция?

Насчет доказательства теорем и constraint solvers - благодаря CTFE все это уже доступно в D в хвост и гриву и уже много лет. Чтобы запустить какой-либо код в D в компайл-тайме нужен весь исходный код (т.е. линковаться с бинарными либами не получится) и все аргументы должны быть известны во время компиляции. А что этот код делает - доказывает теорему или решает систему линейный уравнений, значения не имеет. Причем этот же код и в рантайме можно запускать без каких-либо переделок. У меня сейчас времени нет, но позднее попробую сделать пример с constraint solver во время компиляции. Там же по факту с точки зрения реализации всего навсего дерево, над узлами которого выполняются определенные манипуляции.

проект-специфичный кодогенератор на основе библиотек Clang и метапрограмм на Python

Я вообще думаю, что кодогенерация как минимум равнозначный способ решения задач по сравнению с метапрограммированием. Оно быстрее как минимум и имеет более низкий порог вхождения. Недостаток по сути один - проекто-специфичность, т.е. оправдано только в больших проектах, и больше для приложений, чем для библиотек. Другое дело, что в D можно делать кодогенерацию на самом D без использования каких-либо дополнительных библиотек и тем более языков.

Если сообщество D готово к серьезному рывку вперед в плане поддержки метапрограммирования в большом, я готов помогать в этом направлении и актуальными практическими задачами, и кодом (на С++).

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

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

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

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

В мире Java мы уже активно пользуемся всякими трансформациями и кодогенерациями. А вот в мире С++, из-за охранительной позиции Столлмана относительно экспорта промежуточных представлений Gcc наружу, возможность какой-то автоматизации над исходниками С++ долгое время была юридически невозможна. Clang со своими библиотеками ситуацию сильно изменил, но инерция остается. Инструменты работы с кодом на С++ находятся где-то на уровне 80-х годов прошлого века.

Это «общий случай». Что же касается самой Мемории, то у структур данных есть важная особенность: они создаются под алгоритм. Точнее, под конкретный паттерн обращений к памяти, задаваемый алгоритмом. Еще по некоторым причинам, мощность множества структур данных на много больше мощности множества алгоритмов. Именно поэтому нам и нужны «обобщенные алгоритмы», когда один алгоритм может специализироваться для работы со многими структурами данных. Шаблоны — один из способов задания такого отображения. И для многих нетривиальных случаев даже возможностей полного по Тьюрингу TMP оказывается недостаточно.

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

Вот ты хочешь написать constraint solver на D. Это интересное занятие с точки зрения занимательного программирования, но совершенно бесполезное с практической точки зрения. Ты просто не сможешь написать полнофункциональный CS. Не надо писать. Надо иметь возможность использовать существующие. Это будет на столько практично, на сколько они вообще могут быть практичными.

Метапрограммы не должны быть никак ограничены в плане доступа к вычислительным ресурсам. А их выполнение должно быть поддержано специфичной для них дата-платформой (я упомянул её выше). Это — необходимое условие для их любого нетривиального использования.

Так вот, то, что я назвал «билд-системой», и есть дата-платформа для мета-программ, через которую они могут быть осведомлены о проекте, имеющихся в нем ресурсах и всём прочем. И через которую внешние приложения могут получать доступ к метапрограммам (а-ля language server на стероидах). Этакий «сервер метапрограммирования».

Ты можешь наблюдать мою экспериментальную Jenny Platform. Где я в следующем году буду материализовывать эти идеи, используя Меморию для кодовой модели. И по ходу станет на много понятней, что, зачем и как.

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

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

Это «общий случай». Что же касается самой Мемории, то у структур данных есть важная особенность: они создаются под алгоритм. Точнее, под конкретный паттерн обращений к памяти, задаваемый алгоритмом. Еще по некоторым причинам, мощность множества структур данных на много больше мощности множества алгоритмов. Именно поэтому нам и нужны «обобщенные алгоритмы», когда один алгоритм может специализироваться для работы со многими структурами данных. Шаблоны — один из способов задания такого отображения. И для многих нетривиальных случаев даже возможностей полного по Тьюрингу TMP оказывается недостаточно.

Согласен. В D для этого есть CTFE - практически весь функционал рантайма в время компиляции. Очень мощная вещь.

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

Тоже согласен.

Вот ты хочешь написать constraint solver на D. Это интересное занятие с точки зрения занимательного программирования, но совершенно бесполезное с практической точки зрения. Ты просто не сможешь написать полнофункциональный CS. Не надо писать. Надо иметь возможность использовать существующие. Это будет на столько практично, на сколько они вообще могут быть практичными.

Полноценный солвер на все случаи жизни писать - это, конечно, сама по себе та еще задача. У меня случай проще - несложный солвер для гуя. Я просто точно знаю, что его можно написать и его точно можно запустить в компайл-тайме. Насчет использования готовых я согласен полностью. Но это уже нетривиальная задача и уж точно намного сложнее чем написать солвер для гуев. Запуск Z3 в время компиляции будет большим шагом вперед, но стоит ли оно того, в чем будет профит по сравнению с запуском в рантайме и использовании результатов запуска в последующем процессе сборки? И кодогенерация доступна уже здесь и сейчас.

Ты можешь наблюдать мою экспериментальную Jenny Platform. Где я в следующем году буду материализовывать эти идеи, используя Меморию для кодовой модели. И по ходу станет на много понятней, что, зачем и как.

Надо посмотреть подробнее, все времени не хватает. И еще раз - успехов в этом нелегком деле!

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

Solver может понадобится, например, в двух сценариях.

1. Декларативное программирование. Мы не просто создаем код по шаблону, мы выполняем некоторый поиск в пространстве программ (с помощью того же CS) варианта с заданными свойствами. Это, разумеется, очень долго и непрактично для чего-то большого. Но если solver для наших задач отрабатывает быстро, то почему бы его не использовать?

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

Сейчас оно ограничено не столько тем, что TMP не может обрабатывать большие структуры данных, сколько сложностью самого программирования на языке шаблонов. Там доступны только самые примитивные инструменты отладки. Что-то большое и сложное практически невозможно написать.

2. Метапрограммы не обязательно должны генерировать какой-то код. Они, например, могут проверять определенные инварианты над написанным вручную кодом. Например, use-after-free, или что-то проект-специфичное, что сложно/нельзя выразить теми же концептами С++20. И тут как раз подойдет тот же Z3, хотя это и оверкилл в большинстве случаев.

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

В остальном же, между метапрограммированием и кодогенерацией разницы нет. Метафункции в JP нативно интегрированы в язык и доступны «здесь и сейчас». В Мемории есть codegen, который «на минималках» может делать, в принципе, всё то же самое, но он никак в сам язык не интегрирован. Там можно аннотировать код json-подобными объявлениями, на основе которых codegen может этот код читать, понимать и генерить дополняющие артефакты. Кроме того, codegen это С++-ядро + Python обработчики, что совсем не то же самое, что, например, CTFE в D. А хочется именно такой степени интеграции с языком и его семантикой.

Но это всё в codegen специально так сделано. Это именно «JP на минималках». Зато этот инструмент не интрузивен и допускает использование любого компилятора С++, который удовлетворяет минимальным требованиям Мемории и самого codegen. В JP же метафункции — это диалект, и они не совместимы с апстримом С++.

Сейчас в JP реализованы только сами метафункции, и только как PoC возможности вызывать произвольные функции во время компиляции (интеграция с constexpr). Метафункциям так же доступен парсер С++ для создания фрагментов AST из текста (макросы на тяжелых стероидах). Я пока что на этом проект заморозил. Там основная работа — это интегрированная система сборки (jenny built tool, JBT), которая будет использовать Меморию в как БД для кодовой модели. Но сама Мемория для этого еще не готова пока.

aist1 ★★ ()