Comments 75
assert(Map!((double x) {return x+1.0;},int,double)(ar) == [2.0,3.0,4.0,5.0], "wrong!");
Выглядит страшновато. На пару строк можно перенести?
+2
Это пожелание к статье или вопрос про язык?
Если второе, то да, насколько я знаю, во всех языках в си подобным синтаксисом можно дробить выражения на несколько строк, а если первое, то не уверен, что будет сильно лучше.
Если второе, то да, насколько я знаю, во всех языках в си подобным синтаксисом можно дробить выражения на несколько строк, а если первое, то не уверен, что будет сильно лучше.
+3
В этой строке много текста, но немного смысла. Зачем дробить тривиальное выражение на строки?
0
… эм, судя по минусам, я должен пояснить. Данное выражение содержит многабукв, но с позиции чистой вычислительной логики являет собой простую идиому, которая на языке Haskell, например, будет выглядеть примерно так:
Теперь видно, что ничего страшного тут нет. Если вы активно пользуетесь функциями высшего порядка в своём любимом языке программирования (будь то Haskell, Python или D), то беглое чтение таких идиом — даже на других, более многословных языках — не составляет для вас труда, и разбивка элементарных выражений на строки выглядит скорее вредной, чем полезной.
Уметь бегло читать такие выражения очень важно, поскольку очень важно уметь игнорировать синтаксис и сосредотачиваться на семантике, чтобы сразу же видеть в данном примере не map и \-функцию, а некорректное сравнение чисел с плавающей точкой на равенство.
assert (map (+ 1.0) ar == [2.0,3.0,4.0,5.0]) "good!"
Теперь видно, что ничего страшного тут нет. Если вы активно пользуетесь функциями высшего порядка в своём любимом языке программирования (будь то Haskell, Python или D), то беглое чтение таких идиом — даже на других, более многословных языках — не составляет для вас труда, и разбивка элементарных выражений на строки выглядит скорее вредной, чем полезной.
Уметь бегло читать такие выражения очень важно, поскольку очень важно уметь игнорировать синтаксис и сосредотачиваться на семантике, чтобы сразу же видеть в данном примере не map и \-функцию, а некорректное сравнение чисел с плавающей точкой на равенство.
+2
Я думаю, я понимаю, почему людям не понравилось. Вы утверждаете мало смысла, а на самом деле:
-мы создаем лямбда-функцию
-тут же ее вызываем
-проверяем результирующее значение
-бросаем эксцэпшн с сообщением если не совпало.
Смысла как раз совсем не мало.
И не не надо сравнивать с хаскелом — он вообще чрезвычайно лаконичный язык, с ним что хочешь многословно выглядит :)
-мы создаем лямбда-функцию
-тут же ее вызываем
-проверяем результирующее значение
-бросаем эксцэпшн с сообщением если не совпало.
Смысла как раз совсем не мало.
И не не надо сравнивать с хаскелом — он вообще чрезвычайно лаконичный язык, с ним что хочешь многословно выглядит :)
0
Рискуя снова нарваться, скажу, что, согласно моему мнению, если язык абстрагирует некоторую деятельность, то нужно руководствоваться этими абстракциями (до тех пор, пока абстракция не сломается и не возникнет необходимость залезать вглубь). Приведу пример — реальную строчку из исходного кода ядра Linux:
— мы разыменовываем указатель на массив
— разыменовываем указатель на устройство и идентификатор устройства
— используем идентификатор как индекс массива
— разыменовываем ещё два указателя
— производим побитовый сдвиг
— хитро записываем результат в переменную.
Кошмар! Полэкрана ассемблерных инструкций в результате компиляции одной строчки кода!
И, в принципе, эту строчку можно отрефакторить. Например, вынести cmd->device и hostdata->busy в отдельные переменные. Но зачем? Только первокурснику будет легче читать результирующий код. Опытный системный программист читает эту строчку на одном дыхании и сразу понимает зафиксированные в ней идиомы, а всякие лишние определения переменных, наоборот, замедляют чтение, поскольку приходится расширять удерживаемый в кратковременной памяти контекст.
Некогда об этом же писал Стив Йегг, но о чём он только не писал :-)
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
— мы разыменовываем указатель на массив
— разыменовываем указатель на устройство и идентификатор устройства
— используем идентификатор как индекс массива
— разыменовываем ещё два указателя
— производим побитовый сдвиг
— хитро записываем результат в переменную.
Кошмар! Полэкрана ассемблерных инструкций в результате компиляции одной строчки кода!
И, в принципе, эту строчку можно отрефакторить. Например, вынести cmd->device и hostdata->busy в отдельные переменные. Но зачем? Только первокурснику будет легче читать результирующий код. Опытный системный программист читает эту строчку на одном дыхании и сразу понимает зафиксированные в ней идиомы, а всякие лишние определения переменных, наоборот, замедляют чтение, поскольку приходится расширять удерживаемый в кратковременной памяти контекст.
Некогда об этом же писал Стив Йегг, но о чём он только не писал :-)
+1
Не холивара ради, но такого рода кода из сабжевой строки получится немало. Ну и вообще, число смысла на единицу кода каждым воспринимается по-разному, я на ассемблере программировал, после этого для меня каждая строка кода на C/C++/D/etc наполнена смыслом по самое нехочу.
Строки, написанные мной кажутся мне в самый раз, и я, как автор статьи, имею право решающего голоса, и хоть я и соглашусь с вашими доводами, но те строки удовлетворяют моим эстетическим запросам, потому я так и оставил, но в самом деле. не могу же я всем угодить!
В дополнении замечу, что по-моему вы как-то своими «только первокурснику» и «опытный системный программист» принимаете несколько оскорбительный тон. Получается, все, у кого несовместимые с вашими взгляды — неопытные первокурсники. И именно поэтому вы «рискуете снова нарваться», а не из за отличного от других мнения.
Строки, написанные мной кажутся мне в самый раз, и я, как автор статьи, имею право решающего голоса, и хоть я и соглашусь с вашими доводами, но те строки удовлетворяют моим эстетическим запросам, потому я так и оставил, но в самом деле. не могу же я всем угодить!
В дополнении замечу, что по-моему вы как-то своими «только первокурснику» и «опытный системный программист» принимаете несколько оскорбительный тон. Получается, все, у кого несовместимые с вашими взгляды — неопытные первокурсники. И именно поэтому вы «рискуете снова нарваться», а не из за отличного от других мнения.
0
Конечно, «в дополнение», больше суток не спал, внимательность падает.
-1
Строки, написанные вами, и мне кажутся в самый раз :-)
Ну да, признаю, оценочные суждения тут не совсем уместны, хотя я не ставил своей целью никого оскорбить. Написанное — это исключительно выводы из моего опыта общения с коллегами, я не настаиваю на обобщении моего мнения.
Вообще, на мой взгляд, есть ещё один важный вопрос. Если кому-то в команде, работающей над проектом, сложно читать код, то код нужно рефакторить вне зависимости от регалий всех остальных программистов. А при поддержке всей команды код можно осторожно усложнять. Важны не формальности, а люди и дифференцированный подход. В т. ч. по этой причине я не люблю замечания по форматированию кода в комментариях к статьям о программировании — объективной истины тут не достигнуть, но легко скатиться во вкусовщину и навязывание своего мнения.
Ну да, признаю, оценочные суждения тут не совсем уместны, хотя я не ставил своей целью никого оскорбить. Написанное — это исключительно выводы из моего опыта общения с коллегами, я не настаиваю на обобщении моего мнения.
Вообще, на мой взгляд, есть ещё один важный вопрос. Если кому-то в команде, работающей над проектом, сложно читать код, то код нужно рефакторить вне зависимости от регалий всех остальных программистов. А при поддержке всей команды код можно осторожно усложнять. Важны не формальности, а люди и дифференцированный подход. В т. ч. по этой причине я не люблю замечания по форматированию кода в комментариях к статьям о программировании — объективной истины тут не достигнуть, но легко скатиться во вкусовщину и навязывание своего мнения.
0
И, в добавок, я не понял, в чем вы несогласны со списком действий, приведенных мной выше. Я же полностью учел уровень абстракции языка, я же не заявлял пунктов наврод «создание функционального обьекта-указателя» или «спецификация шаблонной функции конкретными типами».
-1
Упс, забыл еще: вызываем функцию с аргументом в виде этой лямбда-функции и еще одним.
-1
С использование стандартной библиотеки и «настоящего» map будет выглядеть несколько лаконичнее:
Но и код библиотечного map несколько менее тривиален, чем требуется для этой статьи. Зато, как видите, можно указывать функцию не только лямбдой/делегатом, но и обычной строкой. Дополнительная плюшка — map высчитывается лениво.
P.S. equal, а не == т.к. идёт сравнение двух range, строго говоря, являющихся разными типами.
assert( equal( map!("a + 1.0")(ar) , [ 2.0, 3.0, 4.0, 5.0 ] ), "wrong!");
Но и код библиотечного map несколько менее тривиален, чем требуется для этой статьи. Зато, как видите, можно указывать функцию не только лямбдой/делегатом, но и обычной строкой. Дополнительная плюшка — map высчитывается лениво.
P.S. equal, а не == т.к. идёт сравнение двух range, строго говоря, являющихся разными типами.
+1
Со вчерашнего дня, в DMD Git был добавлен синтаксис построения лямбда-функций. Теперь можно писать так:
assert(Map!(x=>x+1.0, int, double)(ar) == [2.0,3.0,4.0,5.0], "wrong!");
0
Если бы название языка начиналось с двоеточия, то он бы пользовался гораздо большей популярностью…
+7
> для этого вызывается наша лямбда-функция [...]. Вызывается каждый раз.
Не правда, всё отлично инлайнится.
Не правда, всё отлично инлайнится.
+1
Это возможно заилайнить. Но если там будет не лямбда в явном виде, а какой-нибудь указатель на функцию, то уже нельзя. Ну или сложно — вдруг кто-то этот указатель переприсвоил другой функции в рантайме? А в D полностью статическое вычисление обеспечено языком.
-1
Еще добавлю: есть разница между «статическое вычисление обеспечено стандартом языка» и «понадеемся, что компилятор сообразит, что выражение можно вычислить статически».
+1
А в стандарте написано что инлайнинг обязан произойти? И кстати, у D, насколько я знаю, нет стандарта…
0
А где я говорил про инлайнинг? Я говорил про гарантию статическово вычисления выражений. Инлайнинг просто после этого легко осуществить.
0
В свое время удивила реализация однобайтовых строк и отсутствие нативной поддержки юникода. Это до сих пор так?
+1
UTF8 рулит. UTF16 всё равно содержит суррогатные пары, так что не даёт простоты. А UTF32 слишком неэкономный. Это к слову об однобайтовых строках. А вот отсутствие поддержки юникода — это плохо.
0
Давненько вы смотрели, однако (:
Когда я в ВУЗе 8 лет назад рассказывал про D, в языке уже была поддержка Unicode. Сейчас и подавно есть: модули std.utf и std.uni специально для работы с Unicode, а так, в общем и целом, все стандартные строковые функции работают с UTF-8, UTF-16 и UTF-32, и исходники тоже могут быть в этих кодировках, причём и в big-, и в little-endian.
Когда я в ВУЗе 8 лет назад рассказывал про D, в языке уже была поддержка Unicode. Сейчас и подавно есть: модули std.utf и std.uni специально для работы с Unicode, а так, в общем и целом, все стандартные строковые функции работают с UTF-8, UTF-16 и UTF-32, и исходники тоже могут быть в этих кодировках, причём и в big-, и в little-endian.
+3
Да, вы определенно обладаете устаревшими данными. Со строками в D как раз все замечательно, мне даже больше чем в C++ нравится, учитывая, что строки не являются чем-то особенным, а просто immutable(char)[]. То есть они просто массивы неизменяемых символов, никаких новых сущностей не вводится. Это хорошо не только эстетически, а, например, тем, что моя реализация Map на них тоже будет работать.
+1
Как там насчет многопоточности? Есть какой-то аналог green threads (легких нитей)?
+2
Читайте официальный сайт, особенно раздел про стандартную библиотеку. Лёгких нитей нет, но обычные треды есть, через модуль core.thread. Я в во всей этой потоковщине не силён, но знаю точно, что по умолчанию все глобальные переменные помещаются в TLS (Thread Local Storage), а чтобы расшарить их между тредами, нужно писать shared (внезапно :)
+1
Насчет потоков я еще глубоко не разбирался, но в язык встроена некоторая поддержка. Как выше написали: shared память, далее, syncronized вычисления, да и чистый функциональный стиль — большое подспорье.
0
Да, еще есть immutable память — такую вообще очень удобно между потоками перекидывать, так как она гарантированно неизменяема.
0
Там всё весьма хорошо с многопоточностью. Green threads нет и, насколько мне известно, не планируется. «D-way» многопоточности на данный момент — message passing. Конечно же поддерживаются и треды в стиле pthread, но в чистом виде к использованию не рекомендуются, т.к. слишком error-prone.
www.informit.com/articles/article.aspx?p=1609144 — опубликованная в открытый доступ глава из книги Александерсу «The D Programming Language», посвящённая concurrency вообще.
www.d-programming-language.org/phobos/std_concurrency.html — стандартная message-passing библиотека
www.d-programming-language.org/phobos/std_parallelism.html — symmetric multiprocessing (SMP)
Есть нативная поддержка в самом языке для синхронизации доступа к данным, основанная на системе типов. Тут парой линков не отделаться, гуглить сайт D по synchronized, shared, immutable
Если возникнут какие-то конкретные практические вопросы — с удовольствием отвечу.
www.informit.com/articles/article.aspx?p=1609144 — опубликованная в открытый доступ глава из книги Александерсу «The D Programming Language», посвящённая concurrency вообще.
www.d-programming-language.org/phobos/std_concurrency.html — стандартная message-passing библиотека
www.d-programming-language.org/phobos/std_parallelism.html — symmetric multiprocessing (SMP)
Есть нативная поддержка в самом языке для синхронизации доступа к данным, основанная на системе типов. Тут парой линков не отделаться, гуглить сайт D по synchronized, shared, immutable
Если возникнут какие-то конкретные практические вопросы — с удовольствием отвечу.
+2
Есть Fibers
+1
Какая у D изюминка, которая цепляет? Я давно еще смотрел этот язык, но так и не нашел той изюминки. Например, у Ruby это RoR, у Go есть routines, а Java, C/C++, Python просто занимают почетное место благодаря зрелости.
Думаю проблема низкой популярности D в отсутствии изюминки, а если она и есть то на неё не заостряют внимание и в итоге ни рыба ни мясо…
Думаю проблема низкой популярности D в отсутствии изюминки, а если она и есть то на неё не заостряют внимание и в итоге ни рыба ни мясо…
0
Это сугубо индивидуально для каждого, это не обьективная причина. Меня зацепил потрясающий дизайи и целостность языка.
+1
Дизайн.
+1
Нет не индивидуально, когда говорят RoR есть ассоциация с Ruby, когда говорят Go есть ассоциация routines, когда говорят Lua есть ассоциация c геймдевом, когда говорят D — ассоциации нет.
-1
Ассоциации в принципе индивидуальны. У меня в lua, например, первая ассоциация — таблицы. И уже потом геймдев.
+2
«Удобство C#, только на выходе не CIL, а нативный код» или Вам не нужен ответ и Вы в любом случае будете отстаивать своё мнение?
Если бы Брайт занялся инструментарием, поддержкой разных архитектур, я давным давно бы перелез с C++ на D.
Если бы Брайт занялся инструментарием, поддержкой разных архитектур, я давным давно бы перелез с C++ на D.
+2
Удобный темплейтинг, компиляция в native код, compile time function evaluation, текстовые миксины. Вам этого мало?
0
Я бы сказал так, изюминка языка как раз в том, что он не заманивает какой-то особой изюминкой — это отлично спроектированный язык для практиков, созданный инженером, а не математиком :) Практичность, мощность и эффективность в нём ценятся выше какой-то Великой Концепции.
Это круто :)
Это круто :)
0
Метапрограммирование. В C++11 так и нет static if.
0
И кстати, такой изюминкой может стать поддержка Native Client, или поддержка любых других модных сегодня штук. Проблема языка в том, что никто не занимается его пиаром.
0
Для язык D существует FrontEnd в LLVM?
Не хватает еще статьи как линковать и использовать с С++.
Все ли сейчас возможно заменить С++ на D, например, при программировании под ARM?
Не хватает еще статьи как линковать и использовать с С++.
Все ли сейчас возможно заменить С++ на D, например, при программировании под ARM?
+1
По поводу статьи — все будет. Есть фронтэнд к gcc.
0
Для язык D существует FrontEnd в LLVM?
Все ли сейчас возможно заменить С++ на D, например, при программировании под ARM?
Ну формально, имея ldc и gdc(фронтенд для gcc) можно собрать и под arm, но на практике еще не встречал упоминаний об успешном применении. У того же gdc в списке багов есть парочка с arm и они давно висят, до сих пор не пофикшены.
P.S. не так давно пробовал собрать gdc для android toolchain — не вышло
Все ли сейчас возможно заменить С++ на D, например, при программировании под ARM?
Ну формально, имея ldc и gdc(фронтенд для gcc) можно собрать и под arm, но на практике еще не встречал упоминаний об успешном применении. У того же gdc в списке багов есть парочка с arm и они давно висят, до сих пор не пофикшены.
P.S. не так давно пробовал собрать gdc для android toolchain — не вышло
+1
А как насчет фрэймвроков, IDE, компиляторов и прочей инфраструктуры, делающей из абстрактного языка реальный инструмент? Расскажите?
Второй вопрос — RTTI
Второй вопрос — RTTI
0
В комментария к прошлой статье я уже обещал сделать статью о инструментарии. Обещал — сделаю. Может, даже следующая будет именно об этом, раз очень активно люди на это упирают.
+1
Всем охота посмотреть вживую, прикинуть для своих задач. Многие избалованы умными IDE и привыкли пользоваться библиотеками/фреймворками для решения типовых задач — писать в «блокноте», компилировать и собирать в консоли, работать с API ОS/DE напрямую никого не заставишь даже на очень хорошем языке :)
0
А вот это неправда! Я на haskell программировал в gedit. И не хэлловорды, а вполне нормальные, хоть и не очень большие программы.
0
Да не то, чтобы даже «умными» :) Я вот visual studio при всем желании умной назвать не могу :) Привычными, скорее. Поэтому я VisualD использовал, а более «умные» плагины для Eclipse — нет.
0
Охохо, извините, но похоже я нашел гораздо более потрясающую воображение тему для статьи, чем скучный рассказ об инструментах :)
Так что не уверен, что будет дальше. Однако, инструменты обязательно будут, может только не в следующий раз.
Так что не уверен, что будет дальше. Однако, инструменты обязательно будут, может только не в следующий раз.
0
RTTI есть:
Выхлоп:
Или интересует что-то более конкретное?
// test.d
import std.stdio;
class Base {}
class Deriv : Base {}
void main()
{
Base o = new Deriv();
writeln( typeid(o) );
}
Выхлоп:
test.Deriv
Или интересует что-то более конкретное?
0
Пример для sort на C++ неправельный. Он не будет компилироваться, потому что auto arr = {...}; выводит тип arr как const int[]. Ну и у массива нет методов begin и end. Поэтому лучше использовать свободные функции begin/end. Учитывая всё это, правельный пример может выглядеть так:
std::vector arr{1, 2, 3, 4};
std::sort(begin(arr), end(arr), [](int a, int b) { return a > b && a < 42; });
Кстати, лямбда здесь инлайнится очень даже хорошо. Лямбда разкрывается в класс с operator(). Но современные компиляторы инлайнят даже если им дать указатель на функцию, когда функция известна во время компиляции.
Это напомнило мне одну презентацию Walter Bright'а, в которой он рассказывал про то как D лучше чем C++. У него был пример на C++ с вектором в несколько строчек, где было допущено 3 ошибки.
+1
Форматирование полностью покоцало мой код. Попробуем еще раз:
std::vector<int> arr{1, 2, 3, 4}; std::sort(begin(arr), end(arr), [](int a, int b) { return a > b && a < 42; });
0
Да, знаю, что неправильный, я так написал, чтобы не зашумлять код техническими деталями и сконцентрировать внимание на смысле. Как сортировать массивы я знаю :)
0
Кстати, если уж об этом, будь я разработчиком стандарта, я бы предложил, чтобы auto в таких случаях дедуцировало именно vecror. Было бы удобнее. Все равно все гайдлайны говорят использовать его вместо сишных массивов.
0
Я не знаю, насколько тебе знаком С++11, но в этом случае (vector<int> arr = {1, 2, 3, 4}), вектор инициализируется через так называемый initialization list. Вектор не единственный класс, который можно инициализировать таким образом. Нет никаких причин, почему именно vector должен дедуцироваться в этом примере.
+1
Нужно стараться всегда быть точным насколько это возможно. Иначе как можно доверять технической информации от человека, который принципиально неточен в деталях?
+1
А про инлайнинг: аргумент про «достаточно умный компилятор» хорошо всем известен. Суть моего сравнения в том, что в C++ это нетривиально. Вернее, не так тривиально, как в D.
-1
> в C++ это нетривиально
Ну, я бы так не сказал. Объекты классов с operator(), или по-другому, функторы, инлайнились всегда особенно хорошо (а лямбда в этом примере превращается именно в функтор).
Ну, я бы так не сказал. Объекты классов с operator(), или по-другому, функторы, инлайнились всегда особенно хорошо (а лямбда в этом примере превращается именно в функтор).
+1
Те люди, которые возмущаются моим недоверием к C++, если это не повод похоливарить, а желание обьяснить мне истину — я знаю, что все замечательно инлайнится. Другое дело, что я всегда в таких ситуациях пытаюсь представить себя на месте человека, который пишет оптимизатор для уже готового компилятора. В D мне «дадут» уже гарантированно вычисленное на стадии компиляции выражение — я его проинлайню без дополнительных умственных усилий. В C++ же мне придется попотеть — как минимум доказать, что это можно инлайнить + мне самому придется вычислять код статически.
0
В C++ описание шаблонов делается в .h файле, таким образом при создании библиотек все равно можно использовать шаблонные функции, так как с библиотекой прилагается и сам .h файл. В D определение и объявление делается в одном файле. При создании библиотеки мне нужно прилагать файл с исходным кодом для использования шаблонной функции?
0
Sign up to leave a comment.
Язык программирования D — продолжение