Комментарии 30
А что вообще в мире на D написано из полезных открытых проектов?
Очевидно, они не на слуху, раз вы о них спрашиваете. Если вы таким образом пытаетесь убедить себя, что этот язык не стоит изучения, то это так себе способ.
Вот открытый проект. Популярный, если мерить популярность по звездочкам: https://github.com/gnunn1/tilix
Вот библиотека для машинного обучения от Netflix:
https://github.com/Netflix/vectorflow
Вас какая-то конкретная сфера интересует?
Вот тут описано почему: 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) и на высоком уровне, давая возможность использовать продвинутые абстракции высокоуровневых/функциональных языков.
На нём откатывается ряд новых технологий.
Откатывается — это отличная опечатка.
Да, опечатка. Я имел в виду "обкатывается"
С GC получилось что-то больше похожее на откат. Начали с GC-based стандартной библиотеки, теперь постепенно переписывают её без использования GC.
Да понятно. Но в контексте развития языка это неистово веселит. Сначала прыжок из ручного управления памятью в GC, стоивший D будущего, теперь вот эта "новая технология", которая у Rust только в проде уже четыре года, а обкатывалась вообще с 2011-го.
А по поводу организации памяти (в С++) — я вообще не заморачиваюсь и как правило обхожусь и без GC, и без RC, и без OB. Просто строю архитектуру программы так, что все объекты, создаваемые через new, организованы в единое дерево; у каждого объекта есть единственный владелец, он же отвечает за удаление. Никаких передач владения нет, объект создается в конкретном месте и в этом же месте и удаляется, при этом я свободно передаю указатели на эти объекты в другие места — просто такие указатели считаются «невладеющими» и нигде не хранятся, а просто используются.
В таком подходе раст для вас идеален, ведь он делает ровно то же самое, только еще статически проверяет, что вы не ошиблись в своих предположениях о жизни ссылок и прочем.
Я вот тоже не понимаю этой озабоченности "сборкой мусора". Где выделил память, там и отдай. Хочешь, встрой проверку на уровне редактора: нет free() — нет компиляции. В чем проблема то…
Что же касается дишных библиотек и их привязки к сборке мусора — тут интересный вопрос: можно ли сделать библиотеки универсальными, такими которые бы содержали код, независимый от наличия или отсутствия сборки мусора в проекте.
константном методе невозможно реализовать ленивую инициализацию
Странная претензия. Объявили функцию, как не меняющую данные, а потом жалуетесь, что данные менять нельзя.
нельзя передать 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 брать из другой библиотеки.
Импортировать прямо в функции нужно только для того, чтобы: а) уменьшить время компиляции в шаблонном коде (тот же phobos) из-за неиспользованных импортов, б) импортировать ближе к месту использования. В остальном это тупая трата экранного места.
Для стека или множества можно взять что-нибудь из std.container.
Ошибки с шаблонами недавно получили апгрейд, так что теперь они должны стать читабельней.
Кстати проблемы с ctRegex должны будут решиться с релизом проекта newCTFE
: https://dlang.org/blog/2017/04/10/the-new-ctfe-engine/
Согласно последнему статусу, автор сейчас работает над прохождением юнит-тестов в стандартной библиотеке. С релизом должны решиться проблемы и с потреблением памяти, и со скоростью компиляции
Так, ну а лайфтаймы завезут?
Владение и заимствование в D