Pull to refresh

Comments 30

Извините за может быть надоевший вопрос:
А что вообще в мире на D написано из полезных открытых проектов?
Ну эту-то страницу я находил. Вопрос был больше про другое. Где популярные открытые проекты, которые на слуху. Типа docker`а на Go.

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

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

Вот тут описано почему: https://www.quora.com/Which-language-has-the-brightest-future-in-replacement-of-C-between-D-Go-and-Rust-And-Why/answer/Andrei-Alexandrescu


Вкратце: D разрабатывался хардкорными инженерами, но в команде не было менеджеров с сильными навыками маркетологов, из-за этого также допускались ошибки в позиционировании языка.


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


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


Тем не менее, программировать на D очень здорово, и после такого опыта обратно на другие языки уже не хочется, особенно на скриптовые. Крутость D в том что он потенциально дает возможность писать одновременно и на низком (вплоть до ASM) и на высоком уровне, давая возможность использовать продвинутые абстракции высокоуровневых/функциональных языков.

Я так понимаю, что D представляет больше академический интерес. На нём откатывается ряд новых технологий.
На нём откатывается ряд новых технологий.

Откатывается — это отличная опечатка.

Да, опечатка. Я имел в виду "обкатывается"

С GC получилось что-то больше похожее на откат. Начали с GC-based стандартной библиотеки, теперь постепенно переписывают её без использования GC.

Да понятно. Но в контексте развития языка это неистово веселит. Сначала прыжок из ручного управления памятью в GC, стоивший D будущего, теперь вот эта "новая технология", которая у Rust только в проде уже четыре года, а обкатывалась вообще с 2011-го.

D весьма неплох, но последнее время тоже скатывается туда же куда и С++ — куча каких-то надстроек, «секретных атрибутов» и т.п. Изначальная стройность языковой концепции потеряна. Особенно это видно изучая исходники компилятора.

А по поводу организации памяти (в С++) — я вообще не заморачиваюсь и как правило обхожусь и без GC, и без RC, и без OB. Просто строю архитектуру программы так, что все объекты, создаваемые через new, организованы в единое дерево; у каждого объекта есть единственный владелец, он же отвечает за удаление. Никаких передач владения нет, объект создается в конкретном месте и в этом же месте и удаляется, при этом я свободно передаю указатели на эти объекты в другие места — просто такие указатели считаются «невладеющими» и нигде не хранятся, а просто используются.

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

Я вот тоже не понимаю этой озабоченности "сборкой мусора". Где выделил память, там и отдай. Хочешь, встрой проверку на уровне редактора: нет free() — нет компиляции. В чем проблема то…

На уровне редактора оно разумеется работать не будет — указатель может быть много раз переприсвоен в другие переменные, и передавать во free() будем совсем не то что получили из malloc().
Что же касается дишных библиотек и их привязки к сборке мусора — тут интересный вопрос: можно ли сделать библиотеки универсальными, такими которые бы содержали код, независимый от наличия или отсутствия сборки мусора в проекте.
У меня двоякое отношение к языку D. С одной стороны он имеет множество очень интересных возможностей и писать на нем весьма приятно и продуктивно. Но с другой стороны, создается впечатление, что язык в принципе довольно плохо проработан. С точки зрения C++ разработчика, в D есть несколько нелепостей, от которых сильно «бомбит». Например квалификатор const. В D отсутствует аналог mutable из C++ и при этом константность транзитивна. Т.е. если указатель константный, значит и данные, на которые он ссылается, тоже изменять нельзя. Из-за этого в константном методе невозможно реализовать ленивую инициализацию, инкремент счетчика ссылок или даже захватить мьютекс. Общепринятая практика в D — по возможности не использовать const вообще. Еще пример — в D нельзя передать rvalue в функцию, которая принимает ссылку на const данные. Из-за этого приходится создавать временные объекты или плодить перегрузки функций в геометрической прогрессии. Так же в D есть квалификаторы типа shared, scope, которые имеют свои проблемы. Ну и самое «вкусное» — это конечно сборщик мусора. Я нисколько не против его наличия, но в случае необходимости его отключения, придется расстаться и с половиной «стандартной» библиотеки phobos. Кроме того, отвалятся встроенные динамические и ассоциативные массивы, а так же классы. Т.е. по сути, существенная часть возможностей превращается в тыкву.
константном методе невозможно реализовать ленивую инициализацию

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


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

https://dlang.org/spec/function.html#inout-functions
Это не то, что вам нужно?


Так же в D есть квалификаторы типа shared, scope, которые имеют свои проблемы.

Какие?

https://youtu.be/TkNep5zHWNw?t=1489
о shared выступающий тоже упомянул
для shared переменных можно вызывать только shared методы, а это тупо удваивает количество кода, и никто их не пишет, т.е. от shared только головняк


еще


  • инициализация по умолчанию для всего "все нули", но для плавающих точек и символов NaN и '\xFF' соотвественно, но оба они не false. см ниже про bool
  • bool это int1 со всеми вытекающими
  • вместе с ним странный int promotion
    enum Week: int { Mon,… Sun };
    auto fn( bool v ) { }
    auto fn( long v ) { }
    fn( Week.Mon ); // fn( false ). WTF?
  • нет string interpolation; именованных параметров; встроенных кортежей (те что из либки не поддерживают деконструкцию); встроенных null-типов как int? с полезными к ним операторами !, ?., ??; нет стандартных асинков; ctRegex иногда дохнет вместе с компилятором, потому что ему не хватает 174GB памяти
  • про асинки. если асинки будут на goroutine-ах, то из них нельзя обращаться к глобальным переменным, потому что они лежат в TLS (если не shared). спорное решение пихать их в TLS
  • лямбда с { return } возвращает новую лямбду, а не просто значение
    () => { float acc;… return acc; } возвращает float delegate(), а не просто вычисленный float. WTF?
    как вернуть из непростой лямбды простое значение? ХЗ
  • в каждую функцию засовывают десяток импортов. потому что в перегружнных функциях рассматриваются вообще только локальные определения. опять головняк
  • нет версионности модулей, потому изобретают experimental модули, которые ты можешь заюзать, но в след релизе они могут уйти куда-то еще и импорты надо переделывать
  • в стандартной либке нет ни Set, ни Stack, ни Deque. есть массив и хэш-словарь. да, из них можно сделать нужное с ошибками и матами, но сразу их выдать нельзя что ли?
  • с nogc/betterC превращается в тыкву, потому что для nogc вообще ничего нет, кроме шаблонов: ни массивов/строк, ни словарей. с чем работать шаблонам и range-м?
  • есть const & immutable, но нет mutable. бредят RefCount, но как его делать?
  • в винде нельзя заюзать рантайм как дллку стандартным путем. если приложение состоит из EXE и DLL, то в приложении 2 рантайма и 2 помойщика. помойщиков можно смерджить стандартным же костылем. но в чем причина не костылить, а скомпилить shared runtime?
  • консервативный помойщик, который можно заменить доп.шагами в точный. но и он сканит весь data seg и иногда вылетает по нехватке памяти, потому что любой лонг в нем считает за возможный указатель. хотелось бы, чтобы сканил только реальные указатели, инфа о типах есть же
  • нет номеров ошибок, которые можно было бы погуглить, потому что текст ошибок меняется, и не всегда понятно, в чем именно ошибка
  • ошибки с шаблонами и mixin-ами выводят простыни текста, попробуй их пойми
  • диктатор не переводит DMD на LLVM, а потому его не колышат ни interop c С++, ни динамическая компиляция и встроенные скрипты, ни WASM
для shared переменных можно вызывать только shared методы, а это тупо удваивает количество кода, и никто их не пишет, т.е.

Вызывать non-shared методы на shared данных не безопасно. Вызывать shared методы на non-shared данных медленно.


от shared только головняк

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


инициализация по умолчанию для всего "все нули", но для плавающих точек и символов NaN и '\xFF' соотвественно

NaN вполне логичен. Максимальное значение для code points видимо для того, чтобы это был не валидный codepoint. Вы немного не правильно понимаете "значение по умолчанию". Это не "все нули", а "значение, несущее меньше всего информации".


bool это int1 со всеми вытекающими

Какими вытекающими? А вы что ожидали? int64?


вместе с ним странный int promotion

Это даже не int promotion. Просто значение энума на этапе компиляции заменяется на число 1, а bool может быть инициализирован 0 и 1, поэтому и матчится на эту сигнатуру. Но поведение всё равно странное, согласен.


нет string interpolation

http://semitwist.com/scriptlike-docs/v0.10.3/scriptlike/core/interp.html
Не так красиво, как в каком-нибудь JS, но всё же.


именованных параметров

Боюсь красиво вписать эту фичу задача не из простых, а профита от неё не очень-то и много.


встроенных кортежей (те что из либки не поддерживают деконструкцию);

Деструктуризация в другой либке:
https://github.com/valmat/vest#tie


встроенных null-типов как int?

https://dlang.org/phobos/std_typecons.html#Nullable


с полезными к ним операторами !, ?., ??

Эти операторы уже заняты для другого.


нет стандартных асинков

И не надо. Есть куда более удобная штука — волокна.
https://dlang.org/phobos/std_concurrency.html


ctRegex иногда дохнет вместе с компилятором

Это на какой регулярке?


() => { float acc;… return acc; } возвращает float delegate(), а не просто вычисленный float. WTF?
как вернуть из непростой лямбды простое значение? ХЗ

Убрать стрелочку: () { float acc;… return acc; }
Если аргументов нет, то и круглые скобки можно убрать: { float acc;… return acc; }
Вы же фактически создаёте два вложенных делегата: через стрелочку и через фигурные скобки. Это не JS :-)


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

Звучит как бред. Покажите код.


нет версионности модулей, потому изобретают experimental модули

Я так понимаю речь про стандартную библиотеку? да, было бы классно, чтобы её вынесли в DUB, а не везли вместе с компилятором.


в стандартной либке нет ни Set, ни Stack, ни Deque. есть массив и хэш-словарь. да, из них можно сделать нужное с ошибками и матами, но сразу их выдать нельзя что ли?

alias Set( Item ) = bool[Item];
alias Stack( Item ) = Item[];
alias Deque( Item ) = Item[];

При желании можно запретить ненужные методы. Какие тут ошибки и маты?


для nogc вообще ничего нет, кроме шаблонов: ни массивов/строк, ни словарей. с чем работать шаблонам и range-м?

https://dlang.org/phobos/std_container_array.html


есть const & immutable, но нет mutable. бредят RefCount, но как его делать?

Не очень понял вашу проблему. Всё, что не помечено как immutable — mutable.

нет кармы на плюсик


  • про tie() для деконструкции кортежей не знал
  • ctRegex https://issues.dlang.org/show_bug.cgi?id=12844
  • Set, Stack, Deque, который вы показали — "ну, нахер"
  • mutable: есть immutable, который же и shared, передаете его куда-нибудь, RC надо поменять (addref/release), но у immutable это надо делать через извращения с cast-ами. с mutable из С++ это делается красиво и понятно.
  • версионность модулей на уровне импортов
    import core.memory!2.0: memcpy; // юзаешь новые функции и "того" же модуля другой версии. нет головняка с std.experimental, который в будущем уйдет. нет name hell. да, фобос должен стать выборочным и скачиваемым. что делать с shared RT, когда все скачиваемо по отдельности?
  • 2 лямбды одной стрелочкой все равно криво. лучше 2 лямбды 2 стрелочками. так более явно видно
    () => { float acc;… return () => acc; } // я возвращаю лямбду из лямбды
  • fiber ну никак не помогает с async/await (слышал про vibe.d)
  • про бред с импортами: неочевидные правила перегрузок методов https://dlang.org/articles/hijack.html
    есть A.fn( long ) и B.fn( real ), включаешь их в модуль C, в котором есть еще fn( string ) и на С.main() { fn( 123 ) } — ошибка "не могу 123 передать как стринг". WTF? вон же методы, хочешь long, хочешь real, "да тут ГТО можно сдавать!". я зря их писал что ли? странно это.
    ну, и некоторые пишут код так, что в каждом методе импортируют все используемые сущности из других модулей по отдельности — куча импортов в методе, за которыми леса не видно.
    импорт в шапке, как в C#, на весь остальной модуль, просто и понятно.

на этом закрою дискуссию, добавить больше нечего.
я юзаю D, но у меня есть к нему претензии.
юзал бы Go/Rust, к ним бы тоже были претензии.
а C#/Kotlin нра без претензий :)

Ознакомьтесь, пожалуйста, с документацией по лямбдам и делегатам: https://dlang.org/spec/expression.html#function_literals


async/await ненужен вообще и помощь с ним не нужна никакая. При чём тут vibe.d я не понял.


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

Подтверждаю что async/await действительно НЕ нужен в языке. Он при желании делается на шаблонах. Проблема в том что теоретически, программа может использовать разные библиотеки для асинхронности, поэтому и планировщик с обработкой ошибок будет разный, и поэтому async/await потенциально будет везде по-разному реализован.


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


D все-таки системный язык, позволяющий делать очень многое, и насильно привязывать его к таким конструкциям как async/await смысла нет

От https://dlang.org/phobos/std_typecons.html#Nullable толку как от козла капусты.
Да, он есть, но в компайл тайме все равно не ограничивает от неправильного использования.


Лучше уж тогда Optional брать из другой библиотеки.

Хочу добавить 3 вещи.

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

Для стека или множества можно взять что-нибудь из std.container.

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

Кстати проблемы с ctRegex должны будут решиться с релизом проекта newCTFE: https://dlang.org/blog/2017/04/10/the-new-ctfe-engine/


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

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

Ну в D и так неплохо с лайфтаймами, так что доработки вряд ли будут большими.
Sign up to leave a comment.

Articles