Почему я выбираю D

Вместо введения


Добрый день, Хабралюди.
Хотел бы поделиться со всеми моим скромным опытом выбора языка программирования для своих проектов. Сразу хочу подчеркнуть – я выбирал язык исходя из собственных нужд, и, вполне вероятно, что ваш выбор в аналогичных условиях может быть другим. Все же я искренне надеюсь, что эта статья будет полезной, так как в ней достаточно подробно и аргументировано проводится сравнение D с C++ и C#, а так же упоминаются свыше десяти различных языков, принадлежащих к различным классам и реализующих различные парадигмы. Сам D разрабатывается как высокоуровневый язык для системного и прикладного программирования.

Так же следует отметить, что существуют две версии D: D1 и D2. D1 стабилен, его обновления затрагивают только исправления ошибок, а в D2 в настоящее время добавляются новые возможности. Так как D2 рекомендован для новых проектов, в статье будет рассматриваться именно он, если не указанно обратное.

Об области применения языков программирования вообще


Итак, приступим. Прежде всего хочу заметить, что выбор языка программирования в первую очередь зависит от круга задач – C/C++/Java/C# скорее всего не сможет заменить JavaScript для веб-страниц или SQL для реляционных баз данных. Хотя тут, пожалуй, нужно сделать оговорку: в принципе можно сделать компилятор или написать библиотеку классов, которые бы по заданным правилам преобразовывали один язык в другой. Так, например, поступила Microsoft при разработке платформы ASP.NET – скрипты для браузера могут быть написаны на любом языке платформы .NET (например, на C#) и затем автоматически преобразованы в соответствующий код на JavaScript. Впрочем, лично я проверял данный функционал только для относительно простых примеров генерации валидаторов форм для браузеров, так что возможно, что для какого-то нестандартного случая придется применять именно JavaScript. С другой стороны, учитывая количество свободно распространяемых библиотек и фреймворков (например, jQuery, MooTools, Prototype и др.), протестированных со всеми современными браузерами, возможно, не стоит изобретать велосипед. И раз уж зашла речь о применимости языков для различных технологий, то, например, можно выбрать функциональный язык программирования, скажем Haskell, для написания операционной системы, но выбор JavaScript в качестве системного языка программирования вероятно будет неразумным. К слову, одна ОС на Haskell’ле уже написана, называется House. Ну а на SQL прикладную программу написать не возможно, так как он не обладает полнотой по Тьюрингу. Transact-SQL уже обладает такой полнотой, но поддерживается только для Microsoft SQL Server и Sybase ASE, так что и этот язык не приспособлен для написания прикладных программ.

Второе – это, конечно же, выбор менеджера проекта. Есть мнение, что C++ настолько популярен только потому, что был популярным лет 5 назад. Другими словами, при выборе языка программирования менеджер проекта скорее всего примет решение в пользу более известного языка (те же Java и C++), чем менее известного (например, Haskell или Common Lisp), даже если последний подходит лучше именно для данного проекта. Спрашивается, почему? Философия очень простая: если менеджер завалит проект на C++, то может попробовать оправдаться тем, что ежегодно на C++ умирают сотни проектов. А с Haskell’ем так не получится, так как в этом случае менеджер сам настоял на использовании сравнительно редко используемой технологии. С моей точки зрения это вообще не оправдание, так как менеджер должен предложить наиболее подходящий язык программирования для данной проблемной области, а не руководствоваться какими-то возможными оправданиями из-за популярности языка. Конечно, это не значит, что нужно программировать на заброшенных и никому не нужных языках. Просто хочу подчеркнуть, что к выбору языка нужно подходить творчески. Например, для решения задач компьютерной алгебры может подойти какой-то из функциональных языков (Common Lisp‎, Scheme, Haskell и др.‎), так как математические формулы на таких языках выглядят в более привычном, «математическом» виде, чем на императивных языках. Вот пример кода на Haskell’ле для вычисления факториала в виде рекуррентной формулы:

factorial :: Integer -> Integer
 factorial 0 = 1
 factorial n | n > 0 = n * factorial (n - 1)

Не правда ли, очень похоже на формулы из учебника? Собственно, свободная система компьютерной алгебры Maxima написана на Common Lisp’е и по своим возможностям сравнима с Maple и Mathematica.
Говоря все это, я лишь хочу подчеркнуть, что выбор языка действительно важен. Не все языки равны между собой, среди них есть более равные. Не верите? Вот пример программы, печатающей «Hello World!», на языке Brainfuck:

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
 .>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
 ------.--------.>+.>.

Сразу хочу пояснить – этот содержащий всего 8 команд эзотерический язык был создан Урбаном Мюллером забавы ради, но, тем не менее, является полным по Тьюрингу, а, значит, позволяет написать то, что не может сделать SQL. Вот только спрашивается: кому это нужно, когда есть десятки более достойных кандидатов? Возможно, именно эту идею хотел подчеркнуть Мюллер, давая языку название, созвучное с известным английским ругательством. Другое возможное объяснение – дать языку запоминающееся имя, чтобы хоть как-то увеличить его популярность.

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

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

Немного о недостатках C#


Начнем по порядку. Почему бы не выбрать C# в качестве языка для прикладного программирования, ведь именно для этого он и предназначен? Основная проблема, которая для меня крайне важна, это компиляция в промежуточный язык Common Intermediate Language (CIL), что делает декомпиляцию тривиальной задачей. Больше того, для этого существуют специальные инструменты. Например, .NET Reflector без ошибок генерирует исходный код на C#/VB.NET/F#, включая сохранение оригинальных названий переменных, функций и классов. Полученный исходный код отличается от авторского разве что отсутствием комментариев. Любители поэкспериментировать могут скачать trial-версию программы с официального сайта.

Итак, если для анализа скомпилированной программы на том же C++ необходимы достаточно глубокие знания, включая умение работы с дизассемблером, то с C# получение исходного кода – вопрос пары минут. Конечно, приверженцам Open Source всё это неважно, но тут тоже можно возразить: если я захочу сделать программу свободной, я опубликую её исходные коды, в противном случае у меня есть основания оставить программу закрытой. В конце концов, далеко не всё ПО – свободное. Тут нужно заметить, что существуют сторонние программы-обфускаторы, способные до неузнаваемости изменить исходный код программы различными дополнительными инструкциями, изменением внутренних интерфейсов и имен переменных, генерированием дополнительных исключительных ситуаций, шифрованием кода и т.п. Всё это позволяет сильно усложнить анализ программы на C#. Из существенных недостатков обфускаторов можно отметить: генерацию более медленного кода, чем исходный, потенциальную возможность внесения ошибки в программу и возможность взлома самого обфускатора (после чего вся его защита становится никому не нужной). Задумайтесь на мгновение: люди годами улучшали компиляторы, пытаясь создать все более качественные и оптимизирующие средства разработки, а тут происходит прямо какая-то регрессия.

Впрочем, вопрос важности компиляции именно в двоичные коды зависит от области применения – если программу не планируется применять за пределами компании-разработчика, то, скорее всего, опасность декомпиляции не будет решающим фактором при выборе языка программирования. И чтобы подвести черту, хотел бы добавить: в стандартной поставке компилятора C# от Microsoft существует инструмент для компиляции программ в двоичные коды, но без исходных кодов на CIL программа все равно работать не будет. Так что для защиты от взлома его использовать невозможно.

Второе, о чём стоит задуматься перед использованием C#, это переносимость полученного кода. Разрешите привести цитату Oktal’а: «Я думаю, что Microsoft назвал технологию .Net для того, чтобы она не показывалась в списках директорий Unix». Не знаю, прав ли автор, но из C# очень легко вызвать функции WinAPI, объекты COM и другие компоненты, которые сделают программу непереносимой. Даже без применения специфичных только для Windows компонентов программа сама по себе не будет запускаться в Unix-системах – для запуска потребуется Mono. Да, конечно же, Mono – это широко известный продукт, но при его использовании проблемы всё же могут появиться. Первое, о чем следует помнить – разработчики Mono будут всегда на шаг позади Microsoft, так как они начинают реализовывать уже выпущенные библиотеки и стандарты. Второе: а им случайно не надоест? Да, я прекрасно понимаю, что это – проект со свободной лицензией, который развивает сообщество, но риск прекращения поддержки все равно существует. Это не повлияет на существующие приложения, но новые программы скорее всего станут непереносимы из-за отсутствия поддержки новых библиотек. Третье, о чем следует вспомнить – отсутствие стандартов на компоненты WinForms, ADO.NET и ASP.NET со стороны Microsoft. Их использование может повлечь за собой юридические претензии со стороны Microsoft, поэтому не рекомендуется использовать их совместно с Mono. Последнее означает, что прекрасный компонент ASP.NET, служащий для построения сайтов различных масштабов, не имеет ровным счетом никаких преимуществ перед тем же PHP. Ну а если вдруг вам все же захочется использовать его в своих проектах, будьте морально готовы к покупке лицензий на серверную версию Windows.

И, наконец, третье, о чем стоить себя спросить: а будет ли Microsoft дальше развивать этот язык? В настоящее время все патенты на C#/CLI принадлежат Microsoft, и отказ от поддержки с её стороны будет означать смерть этому языку. Лично я считаю, что C# будет продолжать развиваться – Microsoft слишком много вложила в этот язык. Но гарантий никто дать не может: в свое время Microsoft отказалась от поддержки Visual Basic, создав вместо него совершенно новый язык Visual Basic .NET без обратной совместимости со своим предшественником. В результате это привело к трагедии для тысяч программистов, работающих на Basic’ке. К тому же, по сообщениям в прессе, в 2015-2016 году Microsoft планирует отказаться от бренда «Windows», создав новую ОС для планшетов, смартфонов, компьютеров, консолей, телевизоров и других устройств, а, значит, языки для разработки под эту ОС тоже могут кануть в небытие.

Лично для меня этих доводов достаточно, чтобы отказаться от использования C#. Не поймите меня неверно: C# – это прекрасный современный язык, но подходит он в первую очередь только для Windows, и то не во всех случаях. Немного подумав, можно прийти к выводу, что использование платформы .NET так же опасно, как и C#. Поэтому лично моё мнение – не стоит писать на языках, ориентированных в первую очередь на эту платформу. Например, Nemerle – хороший язык, в чем-то превосходящий C#, главная особенность которого – развитая система метапрограммирования, и сочетающий в себе возможности функционального и объектно-ориентированного программирования. Но дизайн языка ориентирован в первую очередь на платформу .NET, что ставит под вопрос возможность применения его в ряде проектов. F# – прекрасный пример функционального языка программирования для платформы .NET, в чём-то похожий на Haskell, может подойти для разработки математически-ориентированных систем. Но, опять-таки, платформа .NET ограничивает возможность его применения.

Уважаемые приверженцы C# и платформы .NET! Я прекрасно знаю, что у данных технологий много плюсов, и, в первую очередь, это огромная библиотека классов, с помощью которой можно сделать (почти) всё что угодно. К сожалению, подробный обзор преимуществ платформы .NET потребует написания статьи примерно такого же объёма, поэтому прошу меня извинить за заведомо неполное освещение этой технологии и её возможностей.

Немного о недостатках C++


А почему бы не выбрать C++? Конечно же, это промышленный стандарт, про который слышали все. Но на самом деле у этого языка есть ряд существенных недостатков, некоторые из которых я попробую рассмотреть. Первое, что приходит в голову – этот язык сложен. Точнее, очень сложен. По сравнению с ним работа на C# начинает казаться детской забавой. Судите сами: стандарт только на C занимает около 500 станиц, C++ – около 800, C++11 – около 1300. Если сравнить объем технической документации – этот язык по сложности явно превосходит миксер, швейную машинку и автомобиль, приближаясь скорее к самолётам. Для сравнения, стандарт C# 4.0 занимает всего 505 страниц. В этот момент хочется вспомнить цитату Алана Кёртиса Кэйя (Alan Curtis Kay): «Я изобрел понятие «объектно-ориентированный», но могу заявить, что не имел в виду C++ при этом». В противовес этому можно, конечно, вспомнить создателя C++ Бьерна Страуструпа (Bjarne Stroustrup): «Существуют только два вида языков: те, на которые все жалуются и те, которые никто не использует», но эта цитата звучит скорее как оправдание. D в этом смысле достаточно удобный язык – его дизайн был спроектирован в первую очередь на основе C# и Java. Объём спецификации D1 составляет 223 страницы. Спецификация для D2 поставляется виде html-страниц вместе с компилятором, которая также доступна на официальном сайте www.d-programming-language.org. Кроме того, есть книга Андрея Александреску (Andrei Alexandrescu) «The D Programming Language», которая фактически является описанием стандарта D2 (объем – 492 страницы, в настоящий момент переводится на русский язык). Так вот, сложность самого языка отнюдь не облегчает программирование на нём. В D всё сделано проще, разумней и понятней.

Безопасность прежде всего


Следующий серьёзный минус C++ – плохая проверка кода во время компиляции на предмет ошибок. Другими словами, на C++ очень легко написать код, который будет скомпилирован, но не будет работать верно. Оставим составление полного перечня таких спорных возможностей языка специалистам, ограничившись лишь оператором получения элемента массива operator[] (операция индексирования). То, что этот язык не проверяет границы элементов массива, думаю, ни для кого не секрет. Однако, несмотря на это, ошибки переполнения буфера были, есть и будут появляться в программах на C и C++. И хотя эти ошибки допускают программисты, я считаю, что причина именно в языке, который способствует их появлению. Например, C# всегда делает проверки выхода за пределы массива, что делает подобные ошибки гораздо менее вероятными, но теряя при этом в производительности (переполнение буфера всё ещё потенциально возможно из-за возможных ошибок в реализации компилятора или стандартных библиотек). Библиотека STL решает многие проблемы, но это верно только при её правильном использовании. Например, шаблонный класс vector не проверяет выход за свои границы при использовании операции индексирования (operator[]), для проверки границ необходимо использовать функцию at (Х.М. Дейтел, П.Дж. Дейтел, «Как программировать на C++»). Другими словами, STL – это не панацея.

На самом деле ошибки переполнения буфера – проблема более серьёзная, чем кажется на первый взгляд. Знаменитый Червь Морриса, парализовавший интернет в 1988 году, использовал именно этот тип ошибки (ущерб оценивается в 96 миллионов долларов). Еще один пример: при использовании техники Возвратно-ориентированного программирования (Return-oriented programming) достаточно внедрения всего 2-3 инструкций ассемблера для последующего взлома системы. Другими словами, переполнение буфера даже на один байт может представлять собой уязвимость. Разрешите привести цитату экспертов по безопасности Майкла Ховарда и Дэвида Лебланка из книги «Защищенный код»: «В процессе многих кампаний по безопасности в Microsoft мы настойчиво пропагандировали выявление и при необходимости перенос опасных компонентов, написанных на C или C++, на C# или другой управляемый язык. Это не означает, что код автоматически станет безопасным, но некоторые классы нападений – скорее всего атаки с переполнением буфера – станет намного труднее эксплуатировать. Это же верно по отношению к DoS-атакам на серверы, которые возможны из-за утечки памяти и других ресурсов». Задумайтесь на мгновение: предлагается использовать более медленный, менее функциональный и легко поддающийся дизассемблированию язык только из-за наличия встроенной проверки границ массивов и сборщика мусора.

Тут нужно подчеркнуть разницу между DoS-атакой (Denial of Service, Отказ от обслуживания) и DDoS-атакой (Distributed Denial of Service, Распределённый отказ от обслуживания). DoS-атака, как правило, использует «умные» уловки и уязвимости в сервисе и проводится с небольшого числа компьютеров (возможно, даже с одного). Например, как писалось выше, DoS-атака может быть основана на утечке памяти. Другой пример – атака на файловый сервер, в котором все загружаемые файлы проверяются на наличие вирусов. Сначала создаётся файл размером несколько гигабайт, состоящий из одних нулей, архивируется (размер в архиве – несколько килобайт), закачивается на атакуемый сервер, после чего сервер его распаковывает и пытается проверить антивирусом… DDoS-атакой является попытка вызвать отказ в обслуживании просто за счет перегрузки сервиса таким количеством запросов, на которые он заведомо не рассчитан. Другими словами, это – атака «в лоб», проводящаяся сразу с большого количества машин. Несмотря на то, что существует ряд способов защиты от DDoS-атак, от правильно организованной DDoS-атаки защититься на все 100% невозможно, поэтому становится крайне важной производительность самой службы: чем больше запросов мы можем обработать, тем меньшими будут последствия атаки. В результате этого возникает парадокс: C# за счет лучшего контроля ресурсов позволяет заметно усложнить проведение DoS-атаки, но делает службу более уязвимой к DDoS-атаке из-за более низкой скорости работы.

Но вернёмся к проверке границ массивов в C++. Я прекрасно понимаю, что это – системный язык программирования, и любые дополнительные издержки могут сделать программу в конечном итоге недостаточно производительной. Однако следует подчеркнуть, что критерий производительности важен лишь для конечной release-версии продукта. Версия для отладки предназначена для работы в узком кругу разработчиков программы на тестовых примерах, следовательно, может (и должна) содержать разнообразные проверки и отладочные сообщения, способные повысить её качество и снизить вероятность ошибки (подробнее смотрите в книге Стива Макконнелла «Совершенный код»). Поэтому меня огорчает отсутствие в стандарте C++11 подобных средств хотя бы для debug-версии программы. Однако следует отметить, что существуют сторонние продукты для защиты стека от изменений с целью обнаружения ошибок переполнения в нём, например, расширения компилятора gcc Stackguard и Stack-Smashing Protector (старое название — ProPolice), компиляторы Microsoft Visual Studio и IBM Compiler, которые способны значительно усложнить эксплуатацию уязвимостей. Но потенциальная возможность взлома системы всё же остаётся. К тому же кроме переполнения в стеке возможно переполнение в куче, которое является ничуть не менее опасным. Вывод: единственный надежный способ защититься от взлома – писать правильный код.

Приятно осознавать то, что D выучил урок: в нём есть встроенная поддержка проверки границ массивов для отладочной версии программы, которая отключается при компилировании оптимизированной версии. Другими словами, D сочетает в себе качества двух миров – идеальный выбор для языка системного и прикладного программирования. Но возможности по обеспечению безопасности в D на этом только начинаются. Было бы просто неправильным не упомянуть SafeD – подмножество языка D, запрещающее потенциально опасные операции с памятью, такие как арифметические операции над указателями. Это позволяет гарантировать, что память останется неповрежденной. В сочетании со встроенным сборщиком мусора язык приобретает черты, характерные для C#: ошибки переполнения буфера и DoS-атаки станут вас беспокоить гораздо реже. Разрешите немного перефразировать совет Ховарда и Лебланка: пишите потенциально опасные фрагменты программы на D, и наслаждайтесь безопасным, эффективным и компилируемым языком.

Возможность вызова кода на C/C++ – промышленный стандарт


Пришло время упомянуть еще одну важную черту D: он полностью совместим с кодом C/C++ на уровне объектных файлов, что позволяет получить прямой доступ к функциям и классам, написанным на C/C++ и наоборот. Фактически, стандартная библиотека C является частью стандарта D, правда вместо неё лучше использовать соответствующие функции библиотеки D. Это сделано просто потому, что никто не собирается переписывать тонны C++ кода на D – просто вооружитесь своим любимым компилятором C++ – и готово. Для сравнения, вызов управляемого кода, написанного, например, на C#, из неуправляемого, написанного, например, на C++, возможен через COM-объекты, что с моей точки зрения сложнее, чем просто линковка. Правда тут необходимо отметить, что стандарт C++/CLI добавляет расширенные способы взаимодействия C++ с управляемым кодом, однако это означает использование только компилятора Visual C++ от Microsoft.

Сборка мусора против деструктора


Тему сборки мусора следует осветить подробней. Мне не раз приходилось слышать фразу: «если в язык добавили сборку мусора, значит испортили производительность». Сразу хочется спросить у таких людей: «а тесты вы делали?». Будучи системным языком программирования, D позволяет применять ручное управление памятью (правда, в рамки подмножества SafeD эта возможность уже не входит). В вашем инструментарии появятся перегрузка операторов new и delete и C-стиль управления памятью функциями malloc и free. Кроме того, как правило, быстродействие можно повысить на 90% за счет изменения всего лишь 10% кода (по материалам книги Мартина Фаулера «Рефакторинг. Улучшение существующего кода»). Другими словами, большая часть программы может быть написана с помощью инструкций, безопасно работающих с ресурсами, а небольшой критичный к быстродействию фрагмент может быть тщательно проверен. При этом важно осознавать, что используется один и тот же язык программирования, что упрощает создание, поддержку и сопровождение кода. Кроме того, в больших программах сборка мусора ускоряет разработку, так как программист на C++ тратит много времени (по некоторым источникам – до 50%) на управление памятью. Так что вот вам рекомендация: пишите код, а вопросы производительности оставьте профайлеру, который поможет вам выявить проблемный с точки зрения производительности фрагмент кода.

Также существует ряд алгоритмов, которые просто не могут работать правильно без сборки мусора. Разрешите привести простейший пример: у вас есть абстрактный класс Number, символизирующий какое-то число, и его подклассы: Integer, Long, BigInt, Float, Double, Real, Complex и т.д. Теперь представьте, что где-то в вашей программе появляется примерно такая строчка:

Number* c = a + b;

где a и b – указатели на Number, т.е. фактический тип переменных не известен. При этом предполагается, что если a и b – Long, то в результате получим Long или BigInt (чтобы избежать ошибок переполнения), если Integer и Complex, то Complex, если Double и Double, то Integer, Long, Float или Double (в зависимости от полученного числа знаков после запятой, например 0,5 + 0,5 = 1) и т.д. Скажите, как правильно реализовать функцию operator+(Number* a, Number* b)? Подробный анализ реализаций выходит за рамки этой статьи, но все желающие могут ознакомиться с несколькими возможностями в книге Джеффа Элджера «C++ для настоящих программистов», в главах, посвящённых множественной передаче (и двойной передаче в частности). Хочу лишь отметить, что функция operator+ должна будет создать объект в куче с помощью оператора new, так как вызывающий её код не может ничего знать о фактическом типе объекта c, и поэтому не может выделить память в стеке. Как следствие, нам нужен механизм сборки мусора для освобождения памяти. В данном случае можно применить умные указатели с подсчётом ссылок, но они имеют принципиальные ограничения. Другими словами, встроенной в язык сборки мусора ничто не заменит, и то, что в стандарте C++11 указана поддержка лишь его базовых функций (реализация расширенной сборки мусора в стандарт не вошла), меня отнюдь не радует. Под конец хочется вспомнить цитату Френсиса Бэкона: «Тот, кто не хочет прибегать к новым средствам, должен ожидать новых бед». Да, если вдруг вас заинтересовал предыдущий пример с числами, рекомендую также обратить внимание на CLOS – объектную систему Common Lisp’а, в которой уже имеется встроенная поддержка множественной диспетчеризации.

Деструктор против сборки мусора


Следующее, о чём нужно знать – в D есть RAII (получение ресурса есть инициализация) – характерная для C++ модель управления ресурсами, но отсутствующая в C# и Java. Другими словами, в D есть деструктор, и вызывается он независимо от сборщика мусора. Как следствие, эта парадигма облегчает управление ресурсами (в первую очередь – их освобождение).

Как известно, C# и Java отказались от этой модели, заменив деструкторы завершителями, которые вызываются уже после сборки мусора. Последнее делает невозможным использовать завершители для освобождения критичных для системы ресурсов, так как вызов завершителя может произойти через длительный промежуток времени. Следовательно, освобождать ресурсы нужно явно. «А как же сокрытие информации? Ведь я теперь должен помнить, какие классы требуют явного освобождения ресурсов, а какие – нет! Именно здесь появляются ошибки», – спросите вы, и будете правы. В ответ на это остается разве что развести руками и ответить, что оно было в C++ и есть в D. Правда, в случае неверно написанной программы освобождение ресурсов «неизвестно когда» всё же лучше, чем «никогда», так что однозначный выбор между моделями управления ресурсов в C++ и C#/Java сделать сложно. Возможно, именно поэтому между приверженцами C++ и Java возникает столько споров.

Также в C# возможна ситуация, когда в результате пропуска кода, освобождающего ресурсы явно, вызов завершителя не сможет освободить ресурсы верно (произойдет потеря данных, генерация исключения и т.п.). Например, рассмотрим класс FileStream, являющийся подклассом от Stream и позволяющий писать двоичные данные в файловый поток, и класс StreamWriter, позволяющий писать произвольные данные (например, строки, различные числа, и т.д.) в различные двоичные потоки (в любой из подклассов Stream, например, в FileStream, MemoryStream, NetworkStream и т.д.). В результате мы можем писать произвольные данные в любые потоки, что фактически реализует паттерн проектирования Мост (Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес, «Приемы объектно-ориентированного проектирования. Паттерны проектирования»). Теперь представьте, что во всех этих классах с целью повышения производительности есть встроенные буферы, и данные отправляются на запись только после заполнения буфера (именно так реализованы эти классы в .NET). Теперь добавим ко всему этому ошибку в программе: программист забыл явно освободить ресурсы. После сборки мусора, когда объекты классов FileStream и StreamWriter больше не будут использоваться, произойдёт вызов их завершителей. Но порядок выполнения завершителей в .NET не определён! Это означает, что примерно в 50% случаев завершитель объекта FileStream закроет файл до того, как завершитель объекта StreamWriter финализирует свой буфер. Что теперь должен сделать завершитель объекта StreamWriter, ведь ему просто некуда писать данные? Есть две очевидных возможности: просто проигнорировать, что приведёт к потере данных, или сгенерировать исключение, что приведет к потере данных и аварийному завершению программы (так как данное исключение останется необработанным). С моей точки зрения генерация исключения предпочтительней, так как она упростит отладку программы, но программисты Microsoft со мной не согласны: в своей реализации данных классов они предпочли молчаливую потерю данных. Больше того, для совершения подобной ошибки необязателен пропуск явного освобождения ресурсов, достаточно лишь освободить ресурсы объекта типа FileStream до освобождения ресурсов объекта типа StreamWriter… В такие моменты начинаешь тосковать по правилу C++: «вызовы деструкторов выполняются в порядке, обратном вызовам конструкторов». Вывод: одного лишь сборщика мусора или RAII недостаточно для эффективного управления ресурсами, именно поэтому D поддерживает обе этих технологии.

Вместо заключения


К сожалению, в этой статье не хватило места для обзора ряда особенностей D. Однако хотелось бы пусть и бегло, но всё же их перечислить:
  • Эффективная модель создания многопоточных программ, значительно превосходящая C++ в плане безопасности
  • Мощнейшая система метапрограммирования, сильно упрощающая создание нетривиальных шаблонов. Сравнима по функциональности с макросами в языке Nemerle (которые ничего общего с макрокомандами C/C++ не имеют).
  • Константность и неизменяемость переменных
  • Вычисления на этапе компиляции
  • Наличие черт, характерных для функциональных языков. В частности, в языке есть чистые функции, ленивые вычисления, лямбды, замыкания, функции высших порядков и т.д.
  • Наличие возможности запрета наследования классов и переопределения методов, примерно так же, как в C#/Java
  • Контрактное программирование, способное сильно упростить отладку программ и помочь компилятору лучше оптимизировать код. То, что таких возможностей нет в стандартах C++ и C#, меня огорчает.
  • Встроенная поддержка unit-тестирования, способная помочь при проведении рефакторинга и сопровождении программы
  • Поддержка понятия «модуль» как единицы сборки программы, присутствующая в Ada, C# и Java, но не вошедшая в стандарт C++11
  • Перегрузка операторов, которую использовать проще, чем в C++
  • Поддержка минус бесконечности, бесконечности и NaN (не число) для числовых типов, добавленных в стандарт C99, но не включенных в C++
  • Поддержка кросплатформенности программ (стандартная библиотека D сделана переносимой)
  • Очень быстрая компиляция программ, особенно для больших проектов
  • Генератор документации встроен в компилятор (как, например, и в C#)
  • Профайлер встроен в компилятор, что упрощает поиск «узких» мест в программе
  • Анализ покрытия кода встроен в компилятор, что упрощает отладку программы
  • и многое другое…

Что еще можно почитать?



Дополнительная литература


  • Стив Макконнелл, «Совершенный код»
  • Майкл Ховард и Дэвид Лебланк, «Защищенный код»
  • Майкл Ховард, Дэвид Лебланк и Джон Виега, «19 смертных грехов, угрожающих безопасности программ. Как не допустить типичных ошибок»
  • Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес, «Приемы объектно-ориентированного проектирования. Паттерны проектирования»
  • Мартин Фаулер, «Рефакторинг. Улучшение существующего кода»
  • Х.М. Дейтел, П.Дж. Дейтел, «Как программировать на C++»
  • Джефф Элджер, «C++ для настоящих программистов»

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

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 169

    +33
    Фух, неужели я это дочитал? =)

    Статья неплохая, но, как мне кажется, слишком много отвлечённых разговоров о других языках, их проблемах и парадигмах. Информация про сам D и его плюсы теряется среди всего прочего.
      +5
      Просто не хотел писать короткий список с перечислением особенностей языка, хотелось дать именно сравнение с другими языками. Если Вас интересуют именно особенности D, могу порекомендовать статью на Википедии, ссылку приводил.
        +5
        Нет, я немного не про то.
        Сравнение с другими языками штука хорошая, но в статье больше описание других языков, статья получилась «Почему C++ и C# хуже D».
          +2
          Эх, если начать расписывать достоинства всех языков, то получилось бы страниц 20-30. Наверно, тогда бы никто до конца не дочитал. Итак пришлось статью сильно сократить — ряд особенностей D пришлось просто вынести в раздел «Заключение», хотя те же многопоточное программирование и создание шаблонов были достойны развёрнутого описания.
        +2
        очень похожа на курсовую, например по летающей тарелке. Сперва воспоминания конструкторов, оказавшихся от проектирования воздушных шаров, потом обзор существующих летательных аппаратов, их недостатков и достоинств нашей тарелки. На которые поиски почемуто не хватило места. Если бы я представлял например перл, я бы привел пару связок типа map grep sort и объяснил какие задачи эти конструкции решают.
        0
        А под какие аппаратные архитектуры существуют компиляторы этого языка?
          +1
          Под i386 и x86_64.
          Список поддерживаемых ОС можете посмотреть сами на оф. сайте в разделе загрузки.
          Так же есть сторонние компиляторы под платформы LLVM для D1 и D2 и .NET для D2 и компилятор gdc из проекта gcc. Подробнее см. здесь.
            +2
            GDC в теории поддерживает все архитектуры поддерживаемые GCC, но на практике не везде портировали рантайм языка.

            Люди успешно собирали под ARM и MIPS
            +20
            Уффф. Слишком много воды и размышлений не по делу. Хватило бы развёрнутого (и с примерами) заключения.

            Всё остальное словоблудие (увы, но иначе я это назвать не могу) можно спокойно убрать: зачем рассказывать про полноту по Тьюрингу здесь? Кто-то сомневается, что D тьюринг-полный язык? Зачем вообще упоминать SQL, Brainfuck? Они же совсем мимо кассы…

            А куча утверждений весьма спорна:

            1. Менеджер выбирает C++ не потому, что ему проще отмазаться в случае завала (причина достаточно глупая), а потому, что программисты и знания по языку не являются дефицитом. По языку есть тонна устоявшихся методик программирования, оценки проектов и рисков, известна и подтверждена опытным путём сфера эффективного применения и т.п.

            2. Название Brainfuck не служит цели популяризации языка: язык шуточный и название объясняет саму суть языка. Не более того.

            и т.д.
              +3
              И «realize-версия» =)
                0
                Согласен, вводную часть статьи можно было опустить. Просто нужно было с чего-то начать, подумал, что так будет правильней.
                А можете написать чуть-чуть подробней про «устоявшиеся методики программирования, оценки проектов и рисков, сферу эффективного применения»? Или хотя бы ссылку на литературу дать? Мне правда интересно.
                0
                Так, например, поступила Microsoft при разработке платформы ASP.NET – скрипты для браузера могут быть написаны на любом языке платформы .NET (например, на C#) и затем автоматически преобразованы в соответствующий код на JavaScript.


                Подскажите плз где про это почитать.
                  0
                  возможно автор имел ввиду ASP.NET AJAX с его кодогенерацией.
                    0
                    Если честно, не помню, где именно про это читал. Просто сами попробуйте создать веб-форму и добавить туда валидаторы — соответствующий код на JavaScript должен быть создан автоматически (собственно, в статье я писал именно об этом функционале).
                    Ну а если Вы спрашивали именно о компиляции C# в JavaScript, то можете посмотреть script# для компиляции C# в javascript и jsc compiler для компиляции на IL в javascript, actionscript
                      +2
                      Можно ли убить дракона? Можно, но не убить и не дракона


                      1)Валидаторы не конвертят код на шарпе в джаваскрипт. Если в создаете стандартный валидатор, то он, конечно же добавит на страницу фиксированный даваскрипт. Если валидатор кастомный, то писать джаваскрипт нужно вручную.

                      2)script# не есть часть ASP.NET и не написан MS.
                        0
                        Спасибо, учту. Если не возражаете, добавлю примечание к статье с ссылкой на Вас как на указавшего недочёт.
                          0
                          У MS была попытка под названием Volta www.zdnet.com/blog/microsoft/microsoft-architect-compares-volta-and-googles-gwt/1023

                          Еще есть WebSharper под F# (кстати кто-то из наших делает)
                        +1
                        Есть кстати еще sharpkit.net/ но тоже не от MS. Это я не спорю, а так, вдруг вам интересно :)
                        +4
                        ну где же D с примерами? где пример кроссплатформенной работы с потоками?
                        не могу промолчать про .NET и C# в частности.
                        C# за счет лучшего контроля ресурсов позволяет заметно усложнить проведение DoS-атаки, но делает службу более уязвимой к DDoS-атаке из-за более низкой скорости работы.

                        ну-ну, а если сразу на ассемблере будет написано, то DDoS может пройти мимо.

                        Основная проблема, которая для меня крайне важна, это компиляция в промежуточный язык Common Intermediate Language (CIL), что делает декомпиляцию тривиальной задачей. Больше того, для этого существуют специальные инструменты.

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

                        Не много подумав, можно прийти к выводу, что использование платформы .NET так же опасно, как и C#. Поэтому лично моё мнение – не стоит писать на языках, ориентированных в первую очередь на эту платформу.

                        честно говоря каких-либо вменяемых доводов так и не было, кроме покупки лицензии на windows. т.е. денег на разработку есть, на оплату менеджеров и т.д., а вот $400 на хотя бы Windows Web Server нету.
                        и кстати, почему не вспоминаем сотни undefined behaviour в стандарте самого языка C или C++, где уже надо ориентироваться на сам компилятор. а тут еще и D — темная лошадка.
                          0
                          >> ну где же D с примерами? где пример кроссплатформенной работы с потоками?
                          Надеюсь, войдут в следующую статью.

                          >> ну-ну, а если сразу на ассемблере будет написано, то DDoS может пройти мимо.
                          Тут, конечно, Вы правы, но речь шла именно о совместном использовании средств защиты против DDoS-атак и устойчивости работы самой службы. Согласитесь, всегда есть вероятность пропуска запроса от робота во время DDoS-атаки. Собственно, это я и имел ввиду в статье.

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

                          >> денег на разработку есть, на оплату менеджеров и т.д., а вот $400 на хотя бы Windows Web Server нету
                          Тут уже каждый сам для себя решает, но критика принимается.

                          >> почему не вспоминаем сотни undefined behaviour в стандарте самого языка C или C++
                          Просто решил не лезть в эти дебри. Возможно, в следующий раз упомяну и их тоже.
                            +3
                            В D нет понятия undefined bahavior — это принципиальная позиция автора языка. Но вот со спецификацией слукавили, и сильно — то, что есть для D, и рядом не лежало по полноте со стандартом плюсов. Если детализировать — то объёмы получатся схожими. D очень красивый и умно спроектированный язык, но что он много проще плюсов я бы не сказал. На поверхности — да, но если лезть в нюансы того же duck typing, во взаимодействие с миксинами и модель преопредления опреаторов — ох много там углов… Однако мощно, куда мощнее плюсов в большинстве аспектов.
                            +11
                            Почему-то у вас все преимущества D сводятся к недостаткам С*. =)
                              0
                              Возможно, потому что сам программировал на C# и C++. Как известно, все познается в сравнении, вот и решил написать статью в таком ключе.
                              –3
                              Вы то его может и выбираете, но зато все остальные — нет.
                                +2
                                Статья именно об этом. Удачного Вам программирования на Вашем любимом языке.
                                Может быть, поделитесь с сообществом о своих предпочтениях?
                                  0
                                  C++ и Haskell. Первое — как неизбежное зло (я работаю с околоэмбедщиной и нестандартным железом), второе — как универсальный рабочий инструмент.

                                  И к математике Haskell, вообще говоря, имеет не большее отношение, чем C++ или D.
                                  +4
                                  Смело Вы так, сразу за всех остальных сказать.
                                    +1
                                    Минусы к комментарию заставили меня прочитать статью :)

                                    Я то не против языка D. Мне он даже нравится в качестве замены С++.

                                    Но я имел ввиду то, что не видел, чтобы данный язык использовался где-то в промышленных масштабах. И это самое печальное.
                                    +8
                                    А если от D откажутся? Шансы не меньше чем Micrisoft откажется от C#. Вот захочет человек и откажется.
                                      +1
                                      Вероятность отказа от поддержки всегда существует, тут конечно, Вы правы.
                                      Из плюсов D в этом смысле могу сказать:
                                      1) Развивался с 1999 года, т.е. он старше C#
                                      2) Имеются по меньшей мере 3 открытых разрабатываемых компилятора. Собственно, C++ безопаснее C# именно из-за отсутствия патентных ограничений.
                                      +1
                                      Действительно статье не хвататет конкретизированной практики, например:
                                      одна и та же задача, реализованная в C++, Java и D, где последний явно выигрывает по всем характеристикам.

                                      P.S. Всё равно статья позитивная, рад читать, что новые языки борются за свое место под солнцем и претендуют на то, чтобы потеснить старичков.
                                        0
                                        Можете почитать статью Андрея Александреску «Место для D», там есть несколько интересных примеров. Да и в приведенных мною статьях тоже есть ряд интересных примеров. Но просьба принята, в следующий раз постараюсь сделать упор в том числе на такое сравнение.
                                        +5
                                        Как программисту на C++ было интересно сравнить D и C++:

                                        1. Мне кажется, что про сборку мусора пример не очень удачный.
                                        >> Number* c = a + b;
                                        как вы и предлагаете, можно создавать реальный тип объекта с помощью new. Возможна техника, когда полученный таким образом объект скрывается внутри класса, который управляет его временем жизни (как пример умный указатель). Какие ограничения вы имеете ввиду, говоря о проблеме с умным указателем внутри, скрывающим детали реализации?

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

                                        2. Мне показалось не совсем корректным сравнение размеров стандарта: в стандарте языка C++11 специфицирована STL (standard template library), описание которой начинается с примерно 500-й страницы. То есть по объёму уделённому только языку, получается примерно столько же, сколько C#4. Понятно, что без библиотек сложно программировать, и программисту C#/D точно так же нужно знать библиотеки стандартные для языка. Просто они описаны в стандарте C++, но в отдельной документации для C#.
                                          0
                                          >> Какие ограничения вы имеете ввиду, говоря о проблеме с умным указателем внутри, скрывающим детали реализации?
                                          Если в двух словах, две.
                                          1) При передаче указателя в функцию, которая ничего не знает об умных указателях (например, из внешней библиотеки). Тогда придется блокировать умный указатель, чтобы он не освободил объект до того, как функция вернет управление (актуально в первую очередь для многопоточных программ). Соответственно, возникают проблемы связанные с вызовом функции разблокировки. Например, ее просто могут забыть вызвать или ее вызов будет пропущен в результате генерации исключения.
                                          2) При создании циклических структур данных, например — кольцевых связанных списков, когда класс A ссылается на класс B, а B — на A. Тут, конечно, можно применять другой вид умных указателей (тот же weak_ptr), чтобы разорвать кольцо, но это еще больше усложняет проектировку и эксплуатацию таких классов.

                                          >> Мне показалось не совсем корректным сравнение размеров стандарта
                                          Критика принимается. С другой стороны, думаю, Вы не станете возражать, что синтаксис C++ сложен. Взять хотя бы пример со структурой классов, унаследованных от одного базового Object, который обеспечивает какую-то базовую функциональность (например, toString). Тогда в случае применения тех же умных указателей в программе будет возможен примерно такой код:

                                          smartPrt p;
                                          //Разные функции
                                          p->toString();
                                          p.toString()
                                            0
                                            Всё равно пример неудачный.
                                            Теперь представьте, что где-то в вашей программе появляется примерно такая строчка:

                                            Number* c = a + b;

                                            где a и b – указатели на Number, т.е. фактический тип переменных не известен.

                                            В программе на C++ не может встретиться такая строчка, ибо не разрешено переопределять операторы для указателей. Хотя бы один должен быть классом. Так что данный пример вообще невозможен.
                                              0
                                              Оба должны быть умными указателями, т.е. классами. Извините, что не рассмотрел этот вопрос подробно — все же не основная тема статьи.
                                                +1
                                                Вот. Тогда и ответ будет умным указателем. :)
                                                Или это реализовать таким образом:
                                                class Number;
                                                class Integer : public Number;
                                                class BigInt : public Number;
                                                ...
                                                class AnyNumber
                                                {
                                                public:
                                                ...
                                                private:
                                                    Number* value;
                                                    ...
                                                };
                                                
                                                AnyNumber operator+ (const AnyNumber& a, const AnyNumber& b);

                                                При необходимости в AnyNumber зашивается логика copy-on-write, позволяющая избежать лишних копирований таких типов как BigInt. А напрямую доступ к Number и его потомкам не давать. По сути тоже как бы умный указатель.
                                                  +1
                                                  Да, Вы правы. Спасибо за пример кода. Можете еще книгу Джеффа Элджера полистать, думаю, Вам может быть интересно. Там вообще очень много написано про умные указатели (их там добрый десяток) и сборку мусора в C++.
                                          +3
                                          Например, C# всегда делает проверки выхода за пределы массива, что делает подобные ошибки гораздо менее вероятными, но теряя при этом в производительности (переполнение буфера всё ещё потенциально возможно из-за возможных ошибок в реализации компилятора или стандартных библиотек).
                                          не всегда, а только при необходимости.
                                          var sum = 0;
                                          for (var i=0; i<arr.Length; i++)
                                          {
                                          sum += arr[i];
                                          }

                                          никаких проверок на выход за пределы массива.
                                            0
                                            Приятно читать такие комментарии, сразу видно — в вопросе Вы разбираетесь.
                                            В данном примере лучше использовать цикл foreach, но, думаю, Вы знаете это не хуже меня.
                                            Действительно, компилятор C# «умный», и проверяет границы массивов только при необходимости.
                                            Вот пример кода, где проверка границ массивов будет проведена только один раз (предполагается, что длинна массива больше 5):
                                            var sum = 0;
                                            int maxi = 5;
                                            for (var i=0; i<maxi; i++)
                                            {
                                            sum += arr[i];
                                            }
                                            Тут проверка границ будет проводиться непосредственно перед входом в цикл по формуле
                                            if(maxi<arr.Length)

                                            Все это не вошло в статью с целью хоть как-то сократить ее объем, так как на общую мысль проверки границ массивов не влияет.
                                              +1
                                              Это я к тому, что проверка на выход за границы не так сильно замедляет программу, как кажется на первый взгляд. В большинстве случаев они будут там, где она все равно нужна и была бы в хорошо написанной программе на C
                                                0
                                                Знаете, Вы правы, но не во всех случаях. В первую очередь это касается произвольного доступа в массивах C#. Например, взять тот же алгоритм быстрой сортировки: в нормальной реализации на C будет проверка только для входных данных, в C# — при каждом обращении к массиву.
                                                  +1
                                                  Я не специалист по C#, но отказаться от проверки выхода за границы массива можно даже в Haskell.
                                                    0
                                                    В C# можно делать вставки unsafe кода, для которых проверки выхода за границы массива будут отключены. Впрочем, это одновременно отключает практически все другие проверки компилятора, сборку мусора, и т.п., так что код становится похожим на C++. Собственно, поэтому небезопасный код писать на C# не рекомендовано, и подобная информация не вошла в статью.
                                                      +1
                                                      Ну, не рекомендовано не означает нельзя. Оба языка, в общем-то, уже отошли от принципа «не платить за то, что не используется» — так какая разница, кто отошёл дальше?

                                                      Надо выполнить оптимизацию — выполним.
                                                        0
                                                        Тут, конечно, Вы правы, я не спорю. Просто C# по умолчанию делает проверки, а C++ — нет. Собственно, именно об этом я в статье и писал.
                                                    0
                                                    На C# нормальная реализация алгоритма быстрой сортировки — стандартная библиотека. Там никакой проверки внутри при каждом обращении нет
                                                      0
                                                      Хорошо, а что Вы будете делать, когда потребуется реализовать алгоритм, отсутствующий в стандартной библиотеке, но требующий произвольного доступа к элементам массива?
                                                      Например, при реализации:
                                                      1) алгоритма сортировки слиянием (допустим, потому что этот тип сортировки устойчивый, а реализация быстрой сортировки в C# — неустойчивая)
                                                      2) алгоритма поразрядной сортировки (потому что в ряде случаев она работает быстрее быстрой сортировки)
                                                      3) алгоритма внешней сортировки, например по алгоритму четно-нечетной сортировки слиянием Бэтчера (потому что все данные просто не помещаются в оперативную память)
                                                      4) алгоритма вычисления произведения матриц
                                                      5) алгоритма расчета обратной матрицы
                                                      и т.д.
                                                      Ваши действия?
                                                        0
                                                        Я выкину свои сертификаты в корзину, покаюсь и перейду на D.

                                                        Действия такие же, как и всегда:
                                                        1. Проверить наличие хорошо реализованного в системной/внешней библиотеке алгоритма. (например стабильного Enumerable.OrderBy)
                                                        2. Реализация алгоритма наиболее простым-прямым способом.
                                                        3. При необходимости — профилирование, отладка, оптимизация.

                                                        Если узким местом окажутся проверки границ массива — то в ход пойдет тяжелая артиллерия, unsafe вставки и прочая фигня.

                                                        Только практика показывает, что это все нужно в 1% случаев.
                                                          0
                                                          Сортировка слиянием в C# работает быстрее сортировки Array.Sort. Правда, для этого ее надо написать в unsafe mode на указателях.
                                                +3
                                                Введение есть, и довольно большое, перечисление особенностей вместо заключения есть, а самой статьи нет :)
                                                  +2
                                                  Контрактное программирование, способное сильно упростить отладку программ и помочь компилятору лучше оптимизировать код. То, что таких возможностей нет в стандартах C++ и C#, меня огорчает.

                                                  CodeContracts msdn.microsoft.com/en-us/devlabs/dd491992
                                                    0
                                                    Речь шла о стандартной поставке компиляторов C# и C++.
                                                    Справедливости ради нужно добавить, что для C++ тоже есть библиотеки, добавляющие поддержку контрактного программирования.
                                                      +1
                                                      В 4й фреймворк они уже включены и стороннего ничего ставить не надо. Делается это не через компилятор, а уже после компиляции «дохачивается» IL-код. Правда, из-за этого оно работает не быстро, но все таки это вполне стандартная поставка
                                                    –2
                                                    «Знаменитый Червь Морриса, парализовавший интернет в 1988 году»

                                                    Прямо как в Терминаторе — Моррис заслал свой червь в прошлое, за 2 года до появления интернета, чтобы заранее парализовать его работу?
                                                      +1
                                                        0
                                                        Интернету в прошлом году исполнилось сорок лет. Отправить в 1-й класс учится заново отнимать в столбик.
                                                        –2
                                                        Интересно было почитать, спасибо автору.
                                                        Зацепил вопрос про сборщик мусора. Шутка, конечно удобная, но то, что из-за него теряется производительность ИМХО — факт. GC — работает — значит занимает ресурсы. Тесты, которые вы предлагаете провести — как их проводить? В языке D можно включить/выключить сборщик? А если сравнить по скорости C++ без сборщика и D со сборщиком — получится глупо.

                                                        Вот, пример из жизни про GC:
                                                        Как-то давно писал я мелкие игрушки на C++, Delphi. При грамотно написанном коде — никаких лагов и задержек. все «мегагладко».
                                                        Во всеми ивестном Flash Actionscript 3.0 есть GC. Но даже, если вы напишите на нем что-то ооочень простое, типа несколько шариков летают и умирают — вы заметите небольшие рывки раз в секунду. При большом количестве объектов они не заметны ибо и так все мельтешит, поэтому в играх их не видно.
                                                        Та же история касается и JS с его GC, вот пример
                                                        jsfiddle.net/paul/XQpzU/
                                                        если присмотреться — шарик дергается раз в секунду или две, хотя код — проще некуда.

                                                        так что GC — не есть добро по умолчанию.
                                                          0
                                                          забыл добавить, что когда копался из-за чего эти рывки в JS и AS — знающие люди рассказали мне, что это GC :-)
                                                            0
                                                            К сожалению, я настолько привык к лагающим программам, что эти мини-рывки до сегодняшнего дня не замечал.
                                                              0
                                                              Конечно, они еле заметны, но тем не менее из-за GC сделать гладкую анимацию, как в C++ в JS и AS — невозможно. Интересно, как обстоят дела в D?
                                                              Может, автор статьи напишет что-то простенькое в стиле jsfiddle.net/paul/XQpzU/ для проверки?
                                                                0
                                                                Они не еле заметны, они ужасно заметны, но уже успели прочно войти в нашу жизнь.
                                                                  0
                                                                  Надеюсь, вы не отвернетесь от флэша или хтмл5 :-) Когда я показал эти лаги знакомому флэшеру, тот сказал: «ну что делать?.. забей! они не таки уж и сильные :-)»
                                                                    +2
                                                                    Я боюсь, придется отвернуться от компьютера.
                                                                    Мне уже снятся сны, лагающие на красивых эффектах.
                                                                    Если они будут еще и подергиваться…
                                                                  0
                                                                  Есть такая штука — пул объектов. Поможет в борьбе рпотив GC.
                                                                0
                                                                не знаю, как в D, но в C# сборщик мусора в пользовательских приложениях конкуретный, т.е. ему не нужно усыплять все остальные потоки.
                                                                  –1
                                                                  Включить/выключить — да, можно. Можно писать вообще без использования сборщика мусора — но тогда потребуется своя стандартная библиотека. По скорости — как раз за счёт сборки мусора (и иммутабельности) в D получилась очень эффективная работа со строками — к примеру, подстрока отдается как ссылка, без копирования и подсчета ссылок.
                                                                    +1
                                                                    Это к GC отношения не имеет. Такие строки на C#, на Java, и можно написать такой класс для C++, где нет GC.
                                                                    +2
                                                                    проблема всех VM для JS в том, что на данный момент их GC являются stop the world сборщиками. в таких платформах как .NET GC — Generational.
                                                                    в этом плане у C# проблем нет. более того с .NET 4 дела обстоят еще лучше.
                                                                      0
                                                                      У меня никаких претензий к минусующим, и даже ответные минусы ставить не буду, если они откроются :-). Мне действительно интересно, в чем же ляп, или ошибка, или почему не стоило писать этот комментарий/вопрос?
                                                                      Это отлично, что в D сборщик сделан по другому принципу, нежели, чем в JS или AS. Я, например, этого не знал, возможно кто-то другой — тоже не знает. А возможно, для кого-то эти лаги окажутся открытием.
                                                                        +4
                                                                        Ошибка как минимум в выводах, основанных на незнании. Примитивный mark and sweep GC — это одно, современный GC с регионами и поколениями — совсем другое. Есть и RT Java в конце концов.
                                                                          +1
                                                                          Вроде выводов особо не сделал. Я же не утверждаю, что GC — доктор зло. Просто сказал, что наличие сборщика мусора в языке само по себе ни о чем не говорит. В подтверждение привел пример, когда GC реально «тормозит процесс». И, как выяснилось, я был прав, а вот наличие «современного GC с регионами и поколениями» — уже может о чем-то сказать. И это дописали в комментариях, за это спасибо вам и остальным понимающим людям :-)
                                                                        +1
                                                                        В D можно сборщик мусора отключить.
                                                                          0
                                                                          В немалой степени лаговость GUI андроида обьясняют именно наличием сборщика.
                                                                          Я склонен этому верить.
                                                                          Так что тут палка о двух концах.
                                                                            +1
                                                                            Вы знаете, C++ и Delphi — языки компилируемые, а Flash Actionscript 3.0 — интерпретируемый. Так что, с моей точки зрения, сравнивать производительность C++ и Actionscript просто некорректно.
                                                                              0
                                                                              Согласен с вами, однако, именно GC в AS и JS, как выяснилось приводит к тому, что гладкой анимации не добиться. К счастью в D он устроен иначе и не тормозит процесс. Жаль, что в подтверждение не приводят не «лагающих» примеров =)
                                                                            +4
                                                                            Про отсутствие деструкторов в C# вы зря так категорично написали
                                                                            В большинстве ситуаций интерфейс IDisposable и конструкция using — неплохая альтернатива

                                                                            По крайней мере, у нас за два года работы не было ни одной ошибки, связанной с забытым using
                                                                              –1
                                                                              Кстати есть еще и деструкторы. Но не рекомендуется полагаться на них, т.к. они вызываются недетерминированно. Но как «последний рубеж» освобождения unmanaged ресурса в случае краха (или забытого using) самое то.
                                                                                +2
                                                                                Это не деструкторы (в C++ смысле). В C# именно деструкторов нет. То, что Вы показали — именно завершители, вы же сами пишете, что они вызываются недетерминированно. Просто синтаксис объявления завершителей в C#и деструкторов в C++ фактически одинаковый (~ИмяКласса), отсюда и путаница.
                                                                                  +1
                                                                                  Как уже было сказано, это не деструкторы.
                                                                                  Аналогом плюсового деструктора является именно метод Dispose интерфейса IDisposable.

                                                                                  Конструкция using является аналогом создания объекта на стеке.
                                                                                    0
                                                                                    Согласен, между методом Dispose и деструктором C++ можно провести параллель. Тем не менее, согласитесь, в C# нужно или явно вызывать метод Dispose, или явно использовать конструкцию using, а C++ вызывает деструкторы автоматически.
                                                                                    Хотя я не спорю — при вызове метода Dispose в нужных местах проблем с освобождением ресурсов не будет.
                                                                                +1
                                                                                Статья, ради которой приятно зайти на хабр. Плюсов вряд ли наберет много, тк тема порно и копирастов не раскрыта, но мое «спасибо» автор честно заслужил.
                                                                                  +1
                                                                                  > Судите сами: стандарт только на C занимает около 500 станиц, C++ – около 800, C++11 – около 1300. Если сравнить объем технической документации – этот язык по сложности явно превосходит миксер, швейную машинку и автомобиль, приближаясь скорее к самолётам. Для сравнения, стандарт C# 4.0 занимает всего 505 страниц.

                                                                                  Давайте сделаем честное сравнение. Приложите к спецификации на C# спецификацию на его библиотеки.

                                                                                  И получите следующую картинку (Going Native 2012, keynote day 2): www.habrastorage.com/images/zzz.png
                                                                                    0
                                                                                    Ну знаете, библиотеки — несомненно важная вещь, но они не язык. Разговори идет о сложности языка, а не библиотек. Хотя я тоже против того, чтобы числом страниц мерить сложность. Я читал книгу Страуструпа про С++, ту, которая основная, без продвинутых штук, и читал книгу Алуксандреску про D. Так вот, во-первых мое личное впечатление таково, что первая существенно сложнее, несмотря даже на то, что вторая на английском.
                                                                                    Более того, от книги страуструпа у меня остался такой осадок, что примерно 40-50% информации — описание и способы избежания возможных ошибок.
                                                                                    В кнге про D это примерно 4% — навскидку припоминается только: «Не используйте сишные указатели, это небезопасно». Так что касательно сложности языка автор абсолютно прав. Способов выстрелить себе в ногу при использовании SafeD почти что и нет, а если использовать низкоуровневые штуки — так они просто копируют функциональность си.
                                                                                      +1
                                                                                      > Ну знаете, библиотеки — несомненно важная вещь, но они не язык.

                                                                                      Я говорил о другом. Из упомянутых 1300 страниц C++11 больше половины — STL. Сравнивать со спецификацией на C# по объёму нужно ту часть стандарта, которая описывает язык — а их там остаётся как раз около 500.

                                                                                      > Более того, от книги страуструпа у меня остался такой осадок, что примерно 40-50% информации — описание и способы избежания возможных ошибок.

                                                                                      А у D есть спецификация, при составлении которой дотошно рассмотрена каждая возможная комбинация фич языка? Продуманы undefined behaviors? Есть наработки по статическому анализу? Если нет — то мы просто не знаем, какие паттерны в D являются склонными к ошибкам, поэтому и в книгах об этом не пишут.
                                                                                        0
                                                                                        по D еще мало статистики касательно склонности к ошибкам, но в обшем выстрелить себе в ногу в нем обычно можно, но для этого надо что-нибудь явно сделать. К примеру, хотите экземпляр класса положить на стек — можно, но нужно будет использовать специальный хелпер из библиотеки, который легко ищется/рефакторится.
                                                                                      0
                                                                                      А как коррелируют характеристики языка и объем документации? Если чем меньше документация тем лучше язык то давайте кодить на brainfuck или машине тьюринга. Там документация на страницу влезет размашистым почерком.

                                                                                      Сложность языка не определяется объемом документации по-моему. Ну хотя как, если документации вообще нет, то язык не простой получился. А если она есть и исчерпывающая, то чем её больше, чем больше там примеров и best pracrice тем лучше, разве нет?
                                                                                        0
                                                                                        Критика по поводу объема документации принимается.
                                                                                        Тем не менее, писал в первую очередь о том, что C++ сам по себе сложен.
                                                                                        +3
                                                                                        в нём есть встроенная поддержка проверки границ массивов для отладочной версии программы, которая отключается при компилировании оптимизированной версии

                                                                                        Что толку от проверки, которая включена только в отладочном режиме? Ошибки в безопасности, как правило, при нормальной работе не проявляются, нужно скормить программе специально подобранные данные. Злобные хакеры-то будут смотреть на конечный продукт, в котором компилятор заботливо отключил проверки.
                                                                                        он полностью совместим с кодом C/C++ на уровне объектных файлов, что позволяет получить прямой доступ к функциям и классам, написанным на C/C++ и наоборот

                                                                                        Даже сам C++ несовместим с кодом C++ на уровне объектных файлов. Нестандартизированного манглинга имён уже достаточно, чтобы объектные файлы от разных компиляторов были несовместимы, а уж когда появляются исключения — а они всегда появляются, мало кто использует new(nothrow) — то на переносимости можно смело ставить крест.
                                                                                          0
                                                                                          Автор очень много оставил за скобками. Разумеется, совместимость не полная — она достаточна для того, чтобы без особой мороки связать код на плюсах и D. Ну а если совсем припрёт — придётся имена с явным манглингом писать как extern «C» — так тоже можно. Впрочем, в никсах царит GCC и вроде как совместимый с ним LLVM.
                                                                                            +2
                                                                                            Автор статьи некорректно выразился: проверку границ можно отключить при помощи ключа -noboundscheck, а так она есть и в оптимизированной версии.

                                                                                            Что до совместимости с C++, это только с компилятором от Digital Mars, увы. Впрочем, хоть так можно — и то хорошо: C++ в плане интеграции с другими языками особняком стоит.
                                                                                              0
                                                                                              Если точнее, компилятор Digital Mars D нужно использовать вместе с Digital Mars C для Windows и с GCC для остальных платформ.
                                                                                            0
                                                                                            Всем хорош язык D, особенно возможностью линковаться с сишным кодом в обе стороны (по крайней мере, при использовании компилятора от Digital Mars). Особенно, если закрыть глаза на то, что у языка есть две разных стандартных библиотеки.

                                                                                            Жалко, что нет крупных компаний, которые делают ставку на этот инструмент. Вот у языка Go этой проблемы нет.
                                                                                              0
                                                                                              У Вас немного устаревшие данные. Две стандартных библиотеки (Phobos и Tango) были в D1. В D2 осталась только одна (Phobos), Tango все еще не портирована под D2.
                                                                                            +3
                                                                                            Самое главное — в D нет .h файлов :)
                                                                                              0
                                                                                              Да, Вы правы, нет.
                                                                                              Всю информацию компилятор получает сам из исходного кода. Если необходимо выпустить библиотеку без исходных кодов, то компилятор сам может создать D Interface Files, которые фактически будут играть роль .h файлов.
                                                                                              0
                                                                                              Статья интересная, спасибо. Только маленькая поправочка — SQL с рекурсивными подзапросами полный по тъюрингу (SQL1999).
                                                                                                0
                                                                                                Спасибо за уточнение.
                                                                                                +4
                                                                                                D — очень хороший, продуманный и синтаксически сладкий язык. Меня например, привлекает то, что он компилируемый (несмотря на рост процессоров и железа, интерпретаторы по-прежнему адски медленные, особенно когда построишь большое дерево классов и объектов), но при этом на нем удобно писать.

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

                                                                                                И совместимость с Си-библиотеками — тоже отличная особенность.

                                                                                                Язык очень хорош. Увы, почему-то он не популярен. Видимо, потому, что за ним не стоит ни маркетинга от крупных корпораций, ни компаний вроже 37 signals, ни армии «чайников», ни элитного флера зазнаек-хаскеллистов, ни производителя телефонов, ни линуксоидов.
                                                                                                  +3
                                                                                                  Вот пока язык не найдет себе кого-то кто будет за ним стоять, никто на нем писать не будет. Автор столько распинался на то что в 2016 году майкрософт выкинет виндоус и тысячи c# программистов на мороз, поэтому на нем опасно писать, но совершенно не ясно что будет если автору D — профессиональному разработчику компиляторов надоест его разрабатывать. Ну или начнет делать E.
                                                                                                    +2
                                                                                                    интерпретаторы по-прежнему адски медленные, особенно когда построишь большое дерево классов и объектов
                                                                                                    Большинство серьезных конкурентов D — языки с JIT.
                                                                                                    0
                                                                                                    Вы можете мне объяснить, почему Tango D так зверски работает с XML'ем?

                                                                                                    dotnot.org/blog/archives/2008/03/10/xml-benchmarks-parsequerymutateserialize/
                                                                                                    dotnot.org/blog/archives/2008/03/12/why-is-dtango-so-fast-at-parsing-xml/

                                                                                                    Что-то объяснения про оптимизированную работу строк не сильно впечатляют.
                                                                                                      0
                                                                                                      Tango — библиотека для D1. Выше упомянутая работа со строками относится к D2 — именно там строки сделаны неизменяемыми.
                                                                                                        0
                                                                                                        По оси X на указанном Вами графике — среднее число циклов в секунду.
                                                                                                        >> After the run, I take the average cycle time, and turn that into the followin graph showing cycles per second.

                                                                                                        Другими словами, Tango примерно в 78 раз быстрее Java6 DOM.

                                                                                                        >> Вы можете мне объяснить, почему Tango D так зверски работает с XML'ем?
                                                                                                        Может быть Вы подумали, что по оси X — время?
                                                                                                        0
                                                                                                        Как обстоят дела с GUI библиотеками?
                                                                                                          0
                                                                                                          Есть:
                                                                                                          GtkD — порт GTK+
                                                                                                          DWT — порт SWT
                                                                                                          QtD — порт Qt
                                                                                                          Полный список смотрите здесь.
                                                                                                          0
                                                                                                          Странно, я где-то читал, что
                                                                                                          а. У D проблемы с цеплянием C++ библиотек. Или это относится только к либам, а с объектниками всё нормально?

                                                                                                          б. Сборщик мусора в последних версиях чуть ли не обязателен, а delete считается deprecated. Не так?
                                                                                                            0
                                                                                                            В D1 правда нельзя подключать C++ библиотеки, только C. В D2 также добавили поддержку подключения C++ библиотек.

                                                                                                            Выше в комментариях уже писали, что в D можно отключить сборщик мусора.
                                                                                                              +1
                                                                                                              a.
                                                                                                              «проблем», как таковых, нет, просто, в отличии от поддержки C ABI, поддержка C++ ABI не полная. Поэтому, насколько мне известно, в release-версиях стараются использовать extern «C» прослойку, просто для надёжности. Подробнее здесь: www.d-programming-language.org/cpp_interface.html

                                                                                                              б.
                                                                                                              delete как ключевое слово языка, действительно, deprecated. Причины можно найти на офф. форуме, сейчас, увы, нет времени искать — довольно давно было. Помню жаркую дискуссию. Что, впрочем, ничуть не мешает иметь функциональность delete, если есть такая необходимость ( а она есть редко ).

                                                                                                              Сборщик мусора никогда не был и не будет обязательным. Просто нужно отдавать себе отчёт, в том, что при его полном отключении изрядная часть стандартной библиотеки будет недоступна ( вся память будет утекать ), как и некоторые особо «сладкие» нативные фишки. Язык в таком состоянии больше напоминает better C, нежели better C++.

                                                                                                              Обсуждения насчёт того, что было бы неплохо иметь стандартную библиотеку в режиме reference counting, если сборщик мусора отключен, ведутся постоянно и, в целом, особо никто не возражает. Но соотношение практической ценности этой фичи относительно трудозатрат делают её далеко не приоритетным направлением.
                                                                                                                0
                                                                                                                ***Сборщик мусора никогда не был и не будет обязательным. Просто нужно отдавать себе отчёт, в том, что при его полном отключении изрядная часть стандартной библиотеки будет недоступна ( вся память будет утекать ), как и некоторые особо «сладкие» нативные фишки. Язык в таком состоянии больше напоминает better C, нежели better C++.***

                                                                                                                Жалко, «продолжаем писать на С++». Есть много мест где возможность самостоятельного управления памятью критична по соображениям производительности.
                                                                                                                  +1
                                                                                                                  Возможно, я недостаточно точно выразился.
                                                                                                                  Ручное управление памятью и gc — не противоречащие друг-другу понятия. Даже при включенном gc всегда доступны malloc, free и аллокация на стеке + можно пометить любые блоки памяти как недоступные gc для обхода. Или приостановить gc на какой-то момент для выполнения real-time блока. Это ничем не грозит.

                                                                                                                  Речь же в предыдущем комментарии шла о ситуации, когда gc отсутствует в принципе, не включен druntime на этапе компиляции. Это важно, в основном, только если вы хотите уместить программу на D на какую-нибудь очень embedded платформу, куда garbage collector просто не влезает.
                                                                                                              +6
                                                                                                              > В результате это привело к трагедии для тысяч программистов, работающих на Basic’ке. К тому же, по сообщениям в прессе, в 2015-2016 году Microsoft планирует отказаться от бренда «Windows», создав новую ОС для планшетов, смартфонов, компьютеров, консолей, телевизоров и других устройств, а, значит, языки для разработки под эту ОС тоже могут кануть в небытие.

                                                                                                              Про mono я полностью согласен, но вот про windows… Я не пойму, вы вот представляете это как? Что вот придет 2016 год, выйдет глава майкрософт, скажет: «все, нет больше виндовс, и мы выкидываем ее, еще заодно и c#, вместо них теперь Doors и Ab (а бемоль)»

                                                                                                              Мы все: «А-а-а-а-а-а, как дальше жить?», а вы так гордо «хаха, а я вот сижу на D, и мне ничего не страшно».

                                                                                                              Вам не кажется, что в условиях такого резкого перехода D тоже не выживет? Скорее уж выживет CLR, которую просто портируют на новую Doors. Не будет работать то что завязано на WinAPI, а все что работает в рамках CLR прекрасно заведется и на новой Microsoft Doors с портированной на нее CLR.

                                                                                                              Мне лично такой вариант развития событий представляется более вероятным.

                                                                                                              Еще:
                                                                                                              >Последнее означает, что прекрасный компонент ASP.NET, служащий для построения сайтов различных масштабов, не имеет ровным счетом никаких преимуществ перед тем же PHP.
                                                                                                              Как же это то что .NET завязан на windows, позвольте спросить, означает что он не имеет никаких преимуществ перед php? При всем моем уважении к php .NET даст ему гору очков вперед почти по всем критериям оценки. Начиная с того что c# типизированный, компилируемый и имеет в составе гору встроенных примитивов, в отличии от скудной объектной модели php и заканчивая тем что средства разработки и тестирования под .NET стоят на три лестничных пролета выше чем под php.

                                                                                                              > Ну а если вдруг вам все же захочется использовать его в своих проектах, будьте морально готовы к покупке лицензий на серверную версию Windows.
                                                                                                              Я не понимаю, ну и что? Первая ссылка из гугла показывает что Windows Web Server 2008 стоит 10 765 рублей. Это зарплата одного программиста максимум за неделю. А еще её можно «взять в аренду» в месте с хостингом: арендуя VPS на Windows вы автоматически «арендуете» совершенно лицензионную копию windows. Это стоит от 700р в месяц. Вот то что вижуал студия стоит 25к за рабочее место еще можно было бы рассмотреть, но есть скидки и спец предложения для малого бизнеса. Да и не так это много в масштабах организации. Снять в Москве офис на 2-3 месяца будет стоить столько же сколько купить лицензионного софта на всю команду.
                                                                                                                0
                                                                                                                я мог бы еще кое с чем поспорить, но тогда будет слишком уж длинно
                                                                                                                  0
                                                                                                                  Если есть критика по существу — всегда готов выслушать. Именно в результате подобных дискуссий рождается взаимное понимание.
                                                                                                                  0
                                                                                                                  топику тем не менее поставил плюс. написано хорошо, хоть я и не согласен со многим
                                                                                                                    0
                                                                                                                    >> Скорее уж выживет CLR, которую просто портируют на новую Doors.
                                                                                                                    Вы знаете, .NET почти полностью написана с использованием WinAPI. Просто в документации все методы, реализованные именно с помощью .NET, отмечены специальным значком, и таких методов сравнительно мало. Так что фактически придется переписывать большую часть кода платформы .NET, чтобы ее портировать под другую ОС.

                                                                                                                    >> Как же это то что .NET завязан на windows, позвольте спросить, означает что он не имеет никаких преимуществ перед php?
                                                                                                                    Я имел ввиду, что на Unix-платформах нельзя использовать ASP.NET, а раз его нельзя использовать, то он не даёт никаких преимуществ. Если сравнивать именно языки, то я с Вашей позицией согласен — платформа ASP.NET действительно лучше PHP. Извините, что не выразил свою мысль достаточно внятно.

                                                                                                                    >> Первая ссылка из гугла показывает что Windows Web Server 2008 стоит 10 765 рублей.
                                                                                                                    Собственно, я и имел в виду, что при использовании ASP.NET скорее всего придется покупать лицензионную Windows. А нужно ли это делать — каждый решает для себя сам. У разных ОС свои плюсы и свои минусы, с вашего разрешения, давайте отложим эту дискуссию на другой раз — всё же это не является непосредственной темой статьи.
                                                                                                                      +4
                                                                                                                      > Вы знаете, .NET почти полностью написана с использованием WinAPI. Просто в документации все методы, реализованные именно с помощью .NET, отмечены специальным значком, и таких методов сравнительно мало. Так что фактически придется переписывать большую часть кода платформы .NET, чтобы ее портировать под другую ОС.
                                                                                                                      Ну так оно и предполагалось в общем-то. CLR своего рода прослойка между .NET приложением и конкретной ОС. Отсюда и необходимость JIT компиляции из MSIL. Вполне логично что в windows CLR использует WinApi. А в Unix Mono использует наверное какие-нибудь вызовы ядра. И что в этом плохого? .NET приложению не надо об этом думать. CLR сама как-нибудь разберется, ну не сама, а конечно благодаря труду программистов портировавших её на целевую платформу, но программисту .NET приложения это безразлично. С его точки зрения все «само».

                                                                                                                      Про заначек. Ни разу не видел, как он выглядит? Скиньте ссылку на MSDN где он есть. Не в порядке спора или требования пруфлинка, просто заинтересовали меня, я с удовольствием почитаю про этот значок и отличие методов помеченных им и не помеченных.
                                                                                                                        0
                                                                                                                        Тоже заинтересовал этот значок, где его можно посмотреть в MSDN?
                                                                                                                          0
                                                                                                                          Знаете, видел этот значок в документации к Microsoft Visual Studio 2005 (не Express версия, а обычная). Пользовался именно встроенной в среду справкой, а не ее онлайн версией, для .NET 2.0.
                                                                                                                          Мне кажется, что в то время онлайн версии документации вообще не было, но за последнее утверждение не ручаюсь. Собственно, именно в MS VS 2005 я этот значок и видел. Встречался он почти в каждом классе, примерно у одной-двух функций. Выглядел примерно как оранжевая иконка .NET, всплывающая подсказка гласила примерно следующее: «This method provided by .NET» (за точность фразы ручаться не могу, пишу по памяти), что наводило на простую мысль — остальные методы предоставляются кем-то еще. В литературе встречались утверждения, что .NET почти полностью реализован на основе WinAPI, поэтому в отношении «не помеченных» функций сделал соответствующий вывод.
                                                                                                                          Дальнейшая судьба значка мне неизвестна, возможно, Microsoft отказалась от распространения подобной информации.
                                                                                                                          +2
                                                                                                                          Вы знаете, .NET почти полностью написана с использованием WinAPI
                                                                                                                          А стандартная библиотека С/С++/D/whatever для Windows что, с использованием святого духа написана? Все равно, если мы на платформе Windows открываем файл, мы всегда вызываем CreateFile, а он всегда вызывает NtCreateFile.
                                                                                                                          Если Microsoft откажется от WinAPI, то стандартную библиотеку для С/С++/D/whatever все равно переписать придется.
                                                                                                                        –2
                                                                                                                        «Константность и неизменяемость переменных» — это весело!
                                                                                                                        Веселее (и безопаснее) может быть только язык вообще без переменных.

                                                                                                                        Если не лень — нельзяли вот об этой особенности поподробнее?
                                                                                                                        Какие мега-удобства это привносит (ну, кроме очевидных проблем с многопоточностью)
                                                                                                                          0
                                                                                                                          Вы знаете, как правило в библиотеке D для всех ленивых функций реализован их обычный вариант. Так что Вы сами выбираете, что именно Вам нужно — получить результат сейчас, или отложить вычисления «до востребования».
                                                                                                                          Что касается преимуществ ленивых вычислений, то, если навскидку, возможность оперировать с бесконечно длинными последовательностями.
                                                                                                                          По поводу многопоточных вычислений — Вы неправы (по крайней мере в отношении D). В языке память по умолчанию локальна для потока, чтобы передать данные в другой поток переменную нужно явно объявить разделяемой, что позволяет компилятору проводить ряд проверок.
                                                                                                                          По поводу «константности и неизменяемости переменных» — речь шла о такой возможности (которая, к слову, облегчает написание многопоточных программ). Будете Вы ее применять или нет — зависит от Вас.
                                                                                                                          0
                                                                                                                          Почти весь ряд особенностей есть и в Haskell, и многое другое. Почему же нет раздела «немного о недостатках Haskell»?
                                                                                                                            0
                                                                                                                            Возможно, потому что не было достаточно много опыта программирования на Haskell’е.
                                                                                                                              0
                                                                                                                              Тогда рекомендовал бы приобрести
                                                                                                                              Если выбор и не поменяете, то время проведёте весело :)
                                                                                                                              +1
                                                                                                                              Если некий С-подобный язык и Haskell обладают сравнимым набором особенностей в заданном контексте, какой же окажется естественным выбором для программиста с опытом С/С++?
                                                                                                                                0
                                                                                                                                Я не говорил «сравнимым». Ряд особенностей Haskell куда больше, поэтому не изучить и игнорировать его было бы глупо. А уж выберет ли его потом программист с опытом на C/C++, дело программиста. Я лично выбрал, и далеко не только я (почти все Haskell'исты с C/C++ background'ом).
                                                                                                                                  0
                                                                                                                                  «в заданном контексте»
                                                                                                                                  Ряд особенностей D2 тоже куда больше. Я бегло пробовал и D2, и Haskell, увидел, что D2 покрывает все возможности, что мне интересны в Haskell и не нашел причин изучать его дальше. Более того, Haskell ведь, как я понимаю, всё ещё придерживается строго функционального подхода? Если да, это большой аргумент против.
                                                                                                                                    0
                                                                                                                                    В заданном лично вам контексте — может быть. Но речь не только о вас.
                                                                                                                                    А строгая функциональность — это большой аргумент «за». Но понять это можно только попрограммировав на Haskell.
                                                                                                                                      +1
                                                                                                                                      Заданном автором в статье.
                                                                                                                                      Строгая функциональность — отрада для математика и бессмысленное ограничение для программиста. Особенно для С/С++ программиста. По крайней мере, пока не появятся компьютеры строго функциональные на уровне машинного кода ;) Я вполне понимаю преимущества, которые дают гарантии функционального подхода, особенно для многопоточности. В D2 это есть.
                                                                                                                                      В общем же случае предпочитаю не создавать дополнительных абстракций там, где они не требуются.
                                                                                                                                        0
                                                                                                                                        Строгая функциональность — отрада для математика и бессмысленное ограничение для программиста.

                                                                                                                                        Вы много писали на Haskell?

                                                                                                                                        Особенно для С/С++ программиста.

                                                                                                                                        Странно говорить это C++ программисту, вы не находите?
                                                                                                                                          0
                                                                                                                                          А как насчёт аргументации по существу?
                                                                                                                                          Назовите преимущества строгой функциональности, из-за которой я мотивирован себя ограничивать в способе выражения мыслей.
                                                                                                                                            0
                                                                                                                                            Ну например строгая статическая типизация, по-вашему, это лишняя сущность и бессмысленное ограничение для программиста?

                                                                                                                                            По типу функции Haskell можно видеть не только типы аргументов и результата, но и некоторые важные аспекты функции, наличие состояния, использование ввода-вывода и т.п. Языки с зависимыми типами идут и того дальше, позволяя зафиксировать в типе функции например факт того, что она именно сортирует список, а не делает что-либо ещё.
                                                                                                                                            Причём на существующую систему типов ложатся и исключения, и ввод-вывод, и множественные результаты, и то многое другое, ради чего в других языках городятся специальные конструкции.
                                                                                                                                            Но при этом лишние сущности почему-то именно в Haskell.
                                                                                                                                              +2
                                                                                                                                              1) Строгая типизация не ограничивает возможностей, она лишь заставляет описывать преобразования типов явно. Размен небольшого синтаксического сахара на предсказуемость поведения.
                                                                                                                                              2) Статическая типизация ограничивает, предлагая взамен большую производительность и, в сочетании со строгой, возможность задавать некие контракты.

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

                                                                                                                                              Всё ещё не вижу связи между обязательной строгой функциональностью и списком фич. В D2 тоже по типу функции можно определить некоторые аспекты, такие как pure, nothrow или safe. Обошлись как-то без ограничений.

                                                                                                                                              Хочу заметить, что я нигде не упоминал «лишние сущности», только «бессмысленные ограничения». Это не имеет отношения к теме.
                                                                                                                                                0
                                                                                                                                                никак неявных преобразований целых чисел

                                                                                                                                                Ну если это для вас действительно лишняя сущность, то значит у нас слишком разные взгляды. От неявных преобразований тоже немало ошибок возникает, а ничего плохого в явном касте (очевидном, в первую очередь, для читающего код) я не вижу. А вот в неявном — вижу. Где там floor произойдет? Для этого при чтении в уме надо типы держать, а не просто читать явное floor b + c.

                                                                                                                                                В D2 тоже по типу функции можно определить некоторые аспекты, такие как pure, nothrow или safe. Обошлись как-то без ограничений.

                                                                                                                                                А асинхронный код как синхронный (плоско) там можно писать?
                                                                                                                                                А ФВП позволяет указать, что принимаемая ей функция pure и nothrow (и соот-но проверит ли это компилятор)?

                                                                                                                                                Нет никаких ограничений, вы вполне вольны написать
                                                                                                                                                foo :: MVar Int -> MVar Int -> IO (MVar Int)
                                                                                                                                                Тут и мутабельность, и ввод-вывод.
                                                                                                                                                Если пугает синтаксис, ну так можно ж упросить, это непринципиально.

                                                                                                                                                Ради шутки на Haskell как-то написали модуль, с использованием которого можно писать прямо как на обычном императивном, с циклами, присваиваниями и т.п.
                                                                                                                                                Только это ведь не нужно никому.

                                                                                                                                                Ограничения на практике оказываются полезными.
                                                                                                                                                То, что мутабельный стейт-фул код писать немного напряжнее — это ж хорошо! Задаёт верные приоритеты. Никто не мешает его писать, но:
                                                                                                                                                1. Это явно отражено в типе функции и читатель сразу видит контракты
                                                                                                                                                2. Провоцирует писать более чистый код с декомпозицией (что упрощает, например, тестирование, так как набор чистых функций тестировать — сказка)
                                                                                                                                                3. «Грязный» код пишется лишь тогда, когда действительно нужен, а не везде, где ни попадя.
                                                                                                                                                  0
                                                                                                                                                  Отвечая на ваше сообщение, наткнулся на любопытное поведение компилятора dmd, которое явно стоит внимания. Пардон, нужно некоторое время, чтобы ответить точно.
                                                                                                                                                    +1
                                                                                                                                                    А ФВП позволяет указать, что принимаемая ей функция pure и nothrow (и соот-но проверит ли это компилятор)?
                                                                                                                                                    Да.
                                                                                                                                                    void hof( int function() nothrow pure f ) { }


                                                                                                                                                    А асинхронный код как синхронный (плоско) там можно писать?
                                                                                                                                                    Этот вопрос не понял, мне незнаком термин «плоское написание асинхронного кода».

                                                                                                                                                    Касательно неявных преобразований, как минимум, привычной идиомы if(ptr) мне бы не хватало. Есть некоторое количество преобразований, которые на практике достаточно безопасны и удобны в неявном виде. Я это к тому, что цель языка программирования — быть удобным и практичным, а не предоставить строгую красивую модель.

                                                                                                                                                    Как насчёт вставки в ваш мутабельный пример inline assembler'a? Если уж он действительно такой императивно-мутабельный, а не просто имитирует стиль, взгромождая ещё одну абстракцию?

                                                                                                                                                    Вы исходите из предпосылки, что императивный код «грязнее» и хуже только потому, что он императивный. Кстати, императивный стиль не обязательно подразумевает мутабельность, что вполне показано в D2. До тех пор, пока эта предпосылка существует, нам очень трудно будет найти общий язык.
                                                                                                                                                      +1
                                                                                                                                                      Этот вопрос не понял, мне незнаком термин «плоское написание асинхронного кода».

                                                                                                                                                      Например как тут.
                                                                                                                                                      Т.е. вместо явной передачи callback мы пишем, к примеру
                                                                                                                                                      x <- download "foo";
                                                                                                                                                      lift $ print "foo is downloading"
                                                                                                                                                      y <- download "bar";
                                                                                                                                                      lift $ print "bar is downloading"
                                                                                                                                                      x' <- await x
                                                                                                                                                      y' <- await y
                                                                                                                                                      return (x' + y')

                                                                                                                                                      Это как пример, нафантазировать можно то, что удобнее.

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

                                                                                                                                                      Основной момент в «мне бы не хватало». Поверьте, мне очень многого не хватало из C++ поначалу, но потом оказалось, что это от лукавого :)
                                                                                                                                                      Строгая красивая модель делает язык удобным для чтения, ибо мало частных случаев и каких-то ситуаций, где только знание каких-то нюансов стандарта помогает понять, что происходит. Всё декларируется достаточно явно.

                                                                                                                                                      Как насчёт вставки в ваш мутабельный пример inline assembler'a?

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

                                                                                                                                                      Кстати, никто не мешает и в чистой функции пользоваться state'ом через ST монаду, она позволяет использовать переменные только внутри, поэтому результат гарантированно чистый (причём опять же, никаких хаков). Это похоже на ограничения pure в D.

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

                                                                                                                                                      Вовсе нет. Я исхожу из предпосылки, что чем меньше мы можем наложить контракта на функцию, тем больше вероятность ошибок.
                                                                                                                                                      В динамике никаких ограничений не наложить, в статике дела получше — можно задать типы, но как правило не запретить ввод-вывод и прочее. В Haskell благодаря чистой функциональности и это выводится на уровень системы типов — можем по типу задать эффекты функции. В языках с зависимыми типами (Agda, Coq) можно статически гарантировать практически всё, что угодно. Например, что функция именно конкатенирует списки, а не делает что-либо ещё.
                                                                                                                                                        0
                                                                                                                                                        Прошу прощения за долгие ответы, надо дать себе зарок не ввязываться в дискуссии в разгаре дедлайна.

                                                                                                                                                        import std.stdio;
                                                                                                                                                        import std.file;
                                                                                                                                                        import std.parallelism;
                                                                                                                                                        
                                                                                                                                                        // Синтаксический сахар, которого не нашёл в стандартной либе.
                                                                                                                                                        // Возможно стоить сделать pull request для phobos :)
                                                                                                                                                        auto launch(T)( T new_task )
                                                                                                                                                        {
                                                                                                                                                                struct Launched
                                                                                                                                                                {   
                                                                                                                                                                private:
                                                                                                                                                                        T task;
                                                                                                                                                                public:
                                                                                                                                                                        this(T new_task)
                                                                                                                                                                        {   
                                                                                                                                                                                task = new_task;
                                                                                                                                                                                task.executeInNewThread();
                                                                                                                                                                        }   
                                                                                                                                                        
                                                                                                                                                                        auto result()
                                                                                                                                                                        {   
                                                                                                                                                                                return task.yieldForce();
                                                                                                                                                                        }   
                                                                                                                                                                }   
                                                                                                                                                        
                                                                                                                                                                return Launched(new_task);
                                                                                                                                                        }
                                                                                                                                                        
                                                                                                                                                        void main()
                                                                                                                                                        {
                                                                                                                                                                auto task1 = launch( task!readText("test1.txt") );
                                                                                                                                                                auto task2 = launch( task!readText("test2.txt") );
                                                                                                                                                                write( task1.result ~ task2.result );
                                                                                                                                                        }
                                                                                                                                                        


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

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

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

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

                                                                                                                                                        И хороший практичный язык, ИМХО, должен иметь множество частных случаев и нюансов стандарта. И сам стандарт на тысячи страниц. С тем лишь отличием от С++, что незнание этих нюансов не должно бить новичка по лицу, пока он с ними не знаком.

                                                                                                                                                        Ну ассемблер напрямую не вставить, ибо Haskell куда выше уровнем, да и компилироваться может через LLVM. Но звать сишные функции никто не запрещает
                                                                                                                                                        Я это к тому, что у Haskell и у D несколько разные дизайн-цели. И в D необходимым требованием является то, что встроенный ассемблер должен выглядеть так же естественно, как и функциональный стиль. Равноправное использование всех парадигм.
                                                                                                                                                          0
                                                                                                                                                          Что такое task!readText?

                                                                                                                                                          Я привёл несколько неудачный пример. Вот пример поудачнее:

                                                                                                                                                          do
                                                                                                                                                            send int 1
                                                                                                                                                            x <- receive int
                                                                                                                                                            send string ("hello" ++ show x)
                                                                                                                                                            y <- receive string
                                                                                                                                                            return (show x ++ y)


                                                                                                                                                          send — отправляет сообщение клиенту
                                                                                                                                                          receive — получает сообщение

                                                                                                                                                          Однако receive не блокирует, так как на деле он не ждёт сообщения, а регистрирует callback. Т.е. всё, что ниже receive — автоматом callback.

                                                                                                                                                          Другой пример:
                                                                                                                                                          do
                                                                                                                                                            line <- lines contentOfFile
                                                                                                                                                            word <- words line
                                                                                                                                                            ch <- word
                                                                                                                                                            if ch == 'x' return True else return False


                                                                                                                                                          Аналогичен:
                                                                                                                                                          foreach (line in lines(contentOfFile))
                                                                                                                                                            foreach (word in words(line))
                                                                                                                                                              foreach (ch in word)
                                                                                                                                                                if (ch == 'x') { yield return true; } else { yield return false; }


                                                                                                                                                          Однако тут нет вложенных foreach, это делает монада.

                                                                                                                                                          Контракт может быть полезным, может не быть.

                                                                                                                                                          Однако если у нас нет возможности его наложить, сложно обсуждать его полезность.
                                                                                                                                                          В Agda можно статически гарантировать, что функция, принимающая число, вернёт список с длиной, равной этому числу.
                                                                                                                                                          В Haskell и C++ этого гарантировать нельзя, и в этом смысле Agda более мощный язык.
                                                                                                                                                          Тот факт, что в язык вводят nothrow и pure, говорит о полезности таких контрактов.
                                                                                                                                                          А как в D дела с STM (Software Transactional Memory)? В Haskell это органично вписалось без каких-либо проблем на существующую систему типов. Как это сделать в D так же органично?

                                                                                                                                                          У Haskell выбраны другие умолчания: чистый язык и навешиваемые расширения (STM, IO, State, Cont, list-monad...). На мой взгляд этот путь себя оправдывает.

                                                                                                                                                          А то чувство, когда горы кода после первой же удачной компиляции сразу работают как надо, незабываемо, и про него говорит почти каждый новоявленный Haskell'ист :)
                                                                                                                                                        0
                                                                                                                                                        Haskell, конечно, далёк от идеала. Например, там есть две функции:
                                                                                                                                                        map :: (a -> b) -> [a] -> [b]
                                                                                                                                                        mapM :: Monad m => (a -> m b) -> [a] -> m [b]

                                                                                                                                                        Хотя вообще говоря достаточно лишь одной реализации (первой), а во вторую она превращается автоматически переносом на стрелки Клейсли.
                                                                                                                                                        Т.е. map для списка может быть генерализован до:
                                                                                                                                                        map :: (Arrow a, ArrowChoice a) => a b c -> a [b] [c]

                                                                                                                                                        с одной единственной имплементацией, подходящей как для функций с эффектами, так и для чистых.

                                                                                                                                                        Т.е. любая лямбда-функция типа \f x -> f x + 2 * f x может иметь сразу обобщённый тип. Но в Haskell этого нет, и пока вроде нигде.
                                                                                                                                                      0
                                                                                                                                                      По поводу ограничений, в Haskell даже Data.Dynamic есть, какие ограничения? Хоть динамику используйте.
                                                                                                                                                      Правда практика показывает, что нужно это ну очень редко. Но если очень нужно — то есть.
                                                                                                                                                      Просто переходя с языков, где всё цветёт мутабельностью, по первости непривычно, да, но это не потому, что Haskell плохой, а потому, что инструмент надо сначала изучить, а не кидаться им сразу гвозди забивать, а потом удивляться, что в руке-то не молоток.
                                                                                                                                    –1
                                                                                                                                    Number* c = a + b;

                                                                                                                                    Не смог такое представить, такое скомпилится правильно в одном случае, если a указатель, а b число, иначе как минимум будет варнинг. А представить что оба указатели и надо сложить значения по их адресам я вообще не могу, да и вменяемый сяшник не сможет. Да и оперировать указателями в таком виде, чтобы реализовать свой оператор сложения именно для указателя, да это бред какой-то. Лечиться от этого надо.
                                                                                                                                      0
                                                                                                                                      Вы уж извините, решил не приводить код на пол-страницы. a и b должны быть умными указателями, для которых перегрузка операторов разрешена.
                                                                                                                                        0
                                                                                                                                        NickLion в комментариях написал возможную реализацию, можете посмотреть здесь.
                                                                                                                                      0
                                                                                                                                      Вот меня давно волнует следующий вопрос: если язык так хорош, почему он до сих пор не попал в мейнстрим, в особенности учитывая то, что он вроде как для мэйнстрима и планировался? Как бы с одной стороны понятно, что не помешала бы поддержка кого-нибудь крупного, но, с другой стороны — а почему ее до сих пор нет? И еще вот интересно: может кто из хабрасообщества участвовал в разработке реального проекта на D? Если так — реквестирую хотя бы краткую выжимку такого опыта!

                                                                                                                                      P.S. Вот сейчас специально глянул и не нашел ни одной вакансии «разработчик D» в Москве — поправьте меня, если это не так
                                                                                                                                        0
                                                                                                                                        А как связан мэйнстрим и качество языка?
                                                                                                                                          0
                                                                                                                                          В общем случае никак, разумеется =) Я вот о чем: имеем язык N, язык этот не эзотерический и не предназначенный для решения узкого круга специфических задач. Авторами языка позиционируется как альтернатива плюсам. Многие, в.т.ч. автор статьи, утверждают, что он удобнее плюсов, и приводят ряд аргументов, часть из которых для меня звучит разумно. Отсюда у меня и возникает резонный вопрос: почему язык не популярен? Вопрос, кстати, ни разу не риторический, мне на самом деле это интересно =)
                                                                                                                                            +2
                                                                                                                                            Язык умеренно популярен для личных проектов — на уровне всех остальных не-эзотерических-но-и-не-устоявшихся языков. Что касается индустрии, то там качество языка играет чуть ли не последнюю роль. Важна доступность кадров, надёжность toolchain, полнота библиотек, успешный практический опыт. При этом одна из целевых ниш языка — «замена С++» подразумевает большие, сложные, долгоиграющие проекты, а не что-то формата стартапов, где риск уместен.

                                                                                                                                            И, лично моё мнение, сейчас сложилась патовая ситуация для языка, из-за того, что текущая команда разработчиков не может выдать количественно нужный темп улучшений, не говоря уж о поддержке для корпоративного пользователя. При этом автор языка, Walter Bright всё ещё не хочет отдавать reference toolchain в полный open-source ( полностью открыт только front-end, исходники back-end доступны но проприетарны ), что, несомненно, отпугивает некоторых больших игроков, которые могли бы поддержать проект. Остальным мешает синдром NIH.

                                                                                                                                            Так же нет никакого централизованного пиара, распространение информации о языке, по большей части — community effort. Если бы не сочный язык статей Александреску и его репутация в сообществе С++, возможно, про D слышали бы ещё меньше :)

                                                                                                                                            При этом те, кто может позволить себе выбирать язык для нового проекта и готов к некотором количеству работы с напильником — используют вполне успешно. Например, мне известно, что некий Adam D. Ruppe использует D2 для вполне коммерческой веб-разработки ( во всяком случае так он утверждал сам :) ), и в очень интересном стиле ( github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff ). Если следить за сообщениям на офф. форуме, то такие маленькие «истории успеха» вполне проскакивает.

                                                                                                                                            Но в мэйнстриме играют по другим правилам и я не знаю, в каком направлении надо двигаться D, чтобы преодолеть этот барьер.
                                                                                                                                              0
                                                                                                                                              Доступность кадров, надёжность toolchain, полнота библиотек, успешный практический опыт — это проблемы, которые возникают перед любым новым языком программирования. Причем, редко когда язык занимает абсолютно новую нишу, но удалось же в свое время PHP потеснить Perl, а потом ASP.NET и Ruby / RoR, в свою очередь, потеснить PHP.

                                                                                                                                              Вот объяснение, предложенное вами во втором абзаце, на мой взгляд выглядит достаточно разумно и многое объясняет =)

                                                                                                                                              В любом случае, спасибо за развернутый ответ =)
                                                                                                                                            0
                                                                                                                                            Кстати, глянул ваш профиль, увидел статьи про D. Почитал. Т.к. судя по-всему с языком вы знакомы достаточно плотно, я конкретизирую свой вопрос: можете рассказать о проектах, написанных на D?
                                                                                                                                              0
                                                                                                                                              Какого рода проекты вас больше интересуют?
                                                                                                                                                0
                                                                                                                                                Хм, конечно, наиболее интересен был бы любой опыт коммерческой разработки на D, ежели таковой имеется =) Если вы про тип приложения — мне лично интересно, как язык проявляет себя в разработке GUI-приложений практически любого рода.
                                                                                                                                                  0
                                                                                                                                                  Тогда, увы, не могу помочь. Я слежу, в основном, за развитием библиотек и всего, что касается серверных/сетевых технологий, в силу своего рода занятий. Касательно коммерческого — Adam'а я уже упоминал; несколько человек упоминали, что долгое время используют D для научных вычислений.

                                                                                                                                                  Сам я несколько раз использовал D для написания плагинов, которые в нормальных условиях предполагалось писать на С/С++, во вполне коммерческих проектах. Кодом поделиться не могу, ибо NDA. Могу победить лень и на основе оного написать статью, это максимум.

                                                                                                                                                  Что касается GUI — так оно в большей степени определяется GUI-библиотекой, нежели языком. Тот же GTK он и в D GTK.
                                                                                                                                          +3
                                                                                                                                          От статьи веет пафосом, что еще больше раздражает при наличии фактических ошибок.

                                                                                                                                          Так, например, поступила Microsoft при разработке платформы ASP.NET – скрипты для браузера могут быть написаны на любом языке платформы .NET (например, на C#) и затем автоматически преобразованы в соответствующий код на JavaScript

                                                                                                                                          Ms так не поступала так, как такой функциональности в asp.net нет.

                                                                                                                                          Первое, о чем следует помнить – разработчики Mono будут всегда на шаг позади Microsoft, так как они начинают реализовывать уже выпущенные библиотеки и стандарты.

                                                                                                                                          Не стоит проводить равенство между mono и .net, они пересекающиеся технологии, но не равные. где-то mono задерживается от ms, где-то заметно впереди (managed компилятор от ms выпущен только в прошлом году, а от mono точно был в 2009), а где то вобще не имеет аналогов — monotouch и monodroid. Кстати, на D можно писать приложения под android и iphone, существуют биндинги к gui?

                                                                                                                                          В настоящее время все патенты на C#/CLI принадлежат Microsoft..

                                                                                                                                          Вообще то на c# стандарт есть (Ecma (ECMA-334) и ISO (ISO/IEC 23270:2006)) в отличии от, например, Java. А D стандартизован?

                                                                                                                                          P.S. Я не понимаю, как можно доверять технической статье, которая содержит фактические ошибки, про которые автор пишет «Если честно, не помню, где именно про это читал» это не гуматитарщина, не знаешь — не пиши.
                                                                                                                                            +1
                                                                                                                                            Насчёт android — как раз недавно появился к этому интерес, вот статья по тому, как можно собрать программу для Andoid, используя NDK + gdc. Но без полного портирования druntime и phobos это совсем не так круто, как хотелось бы, увы.
                                                                                                                                            +1
                                                                                                                                            >К тому же, по сообщениям в прессе, в 2015-2016 году Microsoft планирует отказаться от бренда «Windows», создав новую ОС для планшетов, смартфонов, компьютеров, консолей, телевизоров и других устройств, а, значит, языки для разработки под эту ОС тоже могут кануть в небытие.
                                                                                                                                            Мелкософт тратит очень много усилий именно для поддержки обратной совместимости. Нет никаких причин для того, чтобы так резко менять курс. Даже если такое изменение и произойдёт, о нём должны заблаговременно проинформировать, ибо слишком много сейчас у них на .Net завязано.
                                                                                                                                              0
                                                                                                                                              Вы знаете, очень хочу верить, что именно так и будет. В смысле, что будет обратная совместимость.
                                                                                                                                              Однако хочу заметить, что Microsoft уже отказывалась от обратной совместимости, например:
                                                                                                                                              Есть старое программное обеспечение, которое несовместимо с Windows Vista, а также драйверы и устройства.
                                                                                                                                                0
                                                                                                                                                Это всё таки единичные случаи. Если программа написана грамотно, никакие хаки и недокументированная информация в ней не использует, то она будет работать и на следующей версии винды. А так чтобы отказываться от поддержки целой технологии, причём своей же, о таком я не читал.
                                                                                                                                                Ну а по указанной вами ссылке: кто же виноват, что производители устройств не следовали USB спецификациям:)
                                                                                                                                              0
                                                                                                                                              Интересно услышать от автора подобное сравнение с Vala: live.gnome.org/Vala
                                                                                                                                              — переносимость (в рамках gcc)
                                                                                                                                              — компиляция в native (посредством gcc)
                                                                                                                                              — полная интеграция с существующими библиотеками на C (для этого собственно и разработан)
                                                                                                                                              — С# подобный синтаксис и основные концепции
                                                                                                                                              — вместо сборщика мусора и деструкторов выбран усредненный вариант — счетчик ссылок
                                                                                                                                              — компилируется в JavaScript (пока экспериментально)
                                                                                                                                                0
                                                                                                                                                Если оценивать по приведенному списку, то D разве что в JavaScript не компилируется. Почему бы не предоставить линк на обзор Vala? Тогда можно и сравнить, а ставить рядом язык, на котором написано N строк кода и язык, который только что вычитан в интернетах — не практично.
                                                                                                                                                +2
                                                                                                                                                Основная проблема, которая для меня крайне важна, это компиляция в промежуточный язык Common Intermediate Language (CIL), что делает декомпиляцию тривиальной задачей.

                                                                                                                                                И в чем проблема? Сверхсекретные алгоритмы можно вынести на С и вызвать через PInvoke, а ваш код вью-модели очередного диалога никому не интересен. Это не говоря о том, что используя ту же IDA, провести реверс-инженеринг программы, написанной на С/С++ тоже не представляется чем-то особо трудным. Собственно по-этому и появились запаковщики и прочее.

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

                                                                                                                                                Во-первых вы путает Free Soft и Open Source. Во-вторых если у вас есть действительно задача защитить программу от реверс-инженеринга, то ее придется целенаправленно решать не зависимо от того, на какой платформе вы пишете.

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


                                                                                                                                                Самая простая защита от какого-нибудь рефлектора/dotPeek'a это когда делается небольшая программа на С, ей в ресурсы кладутся все ассембли, программа инициализирует CLR и запускает стартовую на выполнение. После чего сам ваш код работает так же, как и без запаковки. Так что вопрос вполне решаемый, хотя на мой взгляд в 90% такая проблема вообще не стоит.

                                                                                                                                                Не знаю, прав ли автор, но из C# очень легко вызвать функции WinAPI, объекты COM и другие компоненты, которые сделают программу непереносимой.


                                                                                                                                                А из С++ или скажем Python вызвать WinAPI разве трудно? Так называемый «system coupling», который трудно развязать, это ошибка архитектуры приложения, никак не связная с языком.

                                                                                                                                                Да, конечно же, Mono – это широко известный продукт, но при его использовании проблемы всё же могут появиться. Первое, о чем следует помнить – разработчики Mono будут всегда на шаг позади Microsoft, так как они начинают реализовывать уже выпущенные библиотеки и стандарты. Второе: а им случайно не надоест? Да, я прекрасно понимаю, что это – проект со свободной лицензией, который развивает сообщество, но риск прекращения поддержки все равно существует.


                                                                                                                                                А вдруг сообществу в целом и Торвальдсу в частности надоест поддерживать linux-kernel? А вдруг гугл завтра обанкротится? Такие предположения в отношении проекта, которому почти 10 лет, звучат как-то странно. Безусловно, в этом мире ни в чем нельзя быть уверен, но надо же как-то жить.

                                                                                                                                                следует вспомнить – отсутствие стандартов на компоненты WinForms, ADO.NET и ASP.NET со стороны Microsoft. Их использование может повлечь за собой юридические претензии со стороны Microsoft, поэтому не рекомендуется использовать их совместно с Mono."


                                                                                                                                                Ну там все тоже не так плохо на самом деле. Ребята с Моно говорят, что если что, просто постараются обойти патенты «Should patent issues ever arise, the Mono project's stated strategy for dealing with them is as follows:
                                                                                                                                                Work around the patent by using a different implementation technique that retains the API, but changes the mechanism; if that is not possible, they would
                                                                                                                                                Remove the pieces of code that were covered by those patents, and also
                                                                                                                                                Find prior art that would render the patent useless.» Ходя судя по тому, как развивается ситуация, MS довольно либеральны в отношении Mono.

                                                                                                                                                а будет ли Microsoft дальше развивать этот язык? В настоящее время все патенты на C#/CLI принадлежат Microsoft, и отказ от поддержки с её стороны будет означать смерть этому языку. Лично я считаю, что C# будет продолжать развиваться – Microsoft слишком много вложила в этот язык. Но гарантий никто дать не может


                                                                                                                                                Во-первых на C# есть стандарт. Делайте свой компилятор и вперед. Развитие C# не привязано к MS, хотя безусловно именно MS двигает его. Что касается гарантий — где гарантии дальнейшего развития любого другого языка?

                                                                                                                                                В результате это привело к трагедии для тысяч программистов, работающих на Basic’ке.


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

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


                                                                                                                                                Во-первых первый раз слышу, чтобы язык был под ОС. .net приложения на С# вполне себе пишутся под ту же WP7(это к слову о переносимости .net). И думаю в новой ос поддержка .net точно так же никуда не денется.

                                                                                                                                                Лично для меня этих доводов достаточно, чтобы отказаться от использования C#


                                                                                                                                                Вы знаете, я согласен, что есть примеры задач, когда C#.net не уместен — это микроконтроллеры, задачи реального времени, работы в ограниченных размерах памяти, необходимость максимальной оптимизации кода под процессор или, например, необходимость быстрого изменения кода без перезапуска приложения. Но доводы, которые привели вы более чем спорны. Что же касается самой статьи, то она скорее должна была называться «Критика С# и С++». Если говорить о D, то интересно было например посмотреть сравнение при решении одних и тех же задач. Ну пример взять простую задачу составление частотного словаря по нескольким файлам. Решить ее с учетом параллельного вычисления и/или распределительного. Сравнить решения на C#\C++\D.

                                                                                                                                                  0
                                                                                                                                                  Программисты на D, как часто встречаетесь с ситуацией, что нужной либы нет и её необходимо писать самостоятельно?
                                                                                                                                                    +2
                                                                                                                                                    Примерно столь же часто, как и программисты на С. Чуть реже.
                                                                                                                                                    Вы недооцениваете значение совместимости ABI.
                                                                                                                                                      0
                                                                                                                                                      Хм, хорошая новость.

                                                                                                                                                      А кто щупал QtD, насколько он полноценен (или, может, есть какие-то его аналоги)?
                                                                                                                                                        0
                                                                                                                                                        Если верить вики, то не вполне.
                                                                                                                                                        Сам ни разу ещё не пробовал писать на D что-либо с GUI, не могу сказать.
                                                                                                                                                          0
                                                                                                                                                          Из аналогов QtD (в смысле, порт библиотеки Qt на D) ничего нет.
                                                                                                                                                          Вот здесь можете посмотреть, какие части Qt уже портированы, какие — еще нет. На данный момент не портированны QtSql, QtScript, QtTest и QtUiTools. Хочу заметить, что в целом поддержка библиотеки улучшается — раньше было больше не портированных компонентов (в частности, не было поддержки QtWebKit).
                                                                                                                                                          Возможно, текущей функциональности Вам будет достаточно, или нужные Вам классы появятся в ближайшем будущем.
                                                                                                                                                          Есть так же порты других GUI библиотек, в том числе:
                                                                                                                                                          GtkD — порт GTK+
                                                                                                                                                          DWT — порт SWT
                                                                                                                                                          wxD — порт wxWidgets
                                                                                                                                                          Возможно, Вам подойдёт что-то из этих библиотек.
                                                                                                                                                      0
                                                                                                                                                      Кстати открылся официальный русский сайт языка программирования D dlang.ru

                                                                                                                                                      Only users with full accounts can post comments. Log in, please.