Разнообразие языков программирования. Изучим их все. D - замена языка C
Здравствуйте! Сегодня, как и обещал в прошлом выпуске, я расскажу вам о новом, набирающем все большую популярность, языке программирования D.
D - системный язык программирования, так же как и язык C и C++. Он был разработан компанией Digital Mars в 1999 году. Синтаксис языка D схож с синтаксисом языков C++, Java. D легок в изучении, поддерживает множество стилей написания кода, объектно-ориентирован.
В чем его преимущество по сравнению с языками С, C++ и другими, ведь для них написано множество
библиотек? Обрадую вас! Язык D поддерживает язык C++ как подмножество, т.е. библиотеки C++ будут полностью рабочими и в языке D. Кроме того, D имеет свой встроенный менеджер памяти, так что теперь вам не придется заботиться о выделении и освобождении памяти, следить за её утечкой. Менеджер памяти сам распределит и выделит память для ваших нужд, а по окончании использования, сам освободит её. Все массивы в D являются динамическими, но получить размер массива или длину строки так же просто как и в C#. Для этого
вам всего лишь нужно обратиться к свойству length массива или строки. Так же из C# взят оператор foreach, с использованием которого так удобно работать со списками и массивами.
Итак
Основные особенности D
Облегчает
написание кода, который без особых усилий может быть перенесен от
компилятора к компилятору, от компьютера к компьютеру, от одной
операционной системы к другой;
Поддержка нескольких подходов к программированию: структурный и объектно-ориентированный, как минимум;
Легкость изучения языка для тех, кто имел дело с языками C и C++;
Обеспечение прямого низкоуровневого доступа к оборудованию;
Наличие контекстно-независимой грамматики;
Легкость создания интернациональных программ;
Возможность создания легковесных и самостоятельных программ.
Возможности, унаследованные от C/C++
Общий
синтаксис языка D схож с синтаксисом C и C++. Это делает его легким его
изучение и портирование кода. Переход от C/C++ к D должен проходить без
проблем. Программисту не придется привыкать к другому подходу написания
кода.
Для того чтобы использовать язык D,
программисту не обязательно ограничивать себя специализированной
виртуальной машиной (VM), как это сделано с Java и Smalltalk. Для D не
существует виртуальной машины. Программы, написанные на D,
компилируются в файлы объектов, которые затем могут быть объединены
линкером в исполняемый файл. D взаимодействует с операционной системой
так, как это делает C. Знакомые инструменты, например make, подойдут и
для разработки на языке D.
Сохранены синтаксис и семантика языков C и C++. D использует те же формы выражений и общий план программ;
Программы
на D могут быть написаны с использованием функционального и
объектно-ориентированного подходов, а также с использованием шаблонов (template metaprogramming) или любой комбинации этих трех подходов;
Поддерживается модель разработки по этапам компиляция/линкование/отладка (compile/link/debug), но ничто не мешает откомпилировать код D в байт-код и интерпретировать его;
Обработка исключений (exception handling).
Опыт использования обработки исключений показывает, что существует
более совершенный стиль обработки ошибок, чем традиционное для языка C
использование кодов ошибок и переменной errno;
Приведение типов
в реальном времени. Отчасти это было реализовано и в C++. Способ
приведения типов в языке D позволяет улучшить процесс сбора мусора и
облегчить процесс отладки;
D поддерживает совместимость с
соглашением о вызове функций в языке C, что делает возможным прямой
доступ из кода на языке D напрямую к программному интерфейсу
операционной системы. В работе с API в D могут быть использованы уже
имеющиеся знания и опыт;
Перегрузка операторов. В языке D можно перегружать операторы с целью расширения списка операций над пользовательскими данными;
Использование шаблонов.
Шаблоны дают возможность создавать обобщенные функции, оперирующие
независящими от типа данных переменными. В языке D шаблоны лишены
недостатков шаблонов из языка C++.
Чего нет в языке D
Совместимость
с исходным кодом языка C. Уже существует языки программирования,
совместимые с исходным кодом, написанным на языке C (C++ и ObjectiveC).
Дальнейшая работа в этом направлении препятствует реализации
существенных возможностей;
Препроцессор. Для расширения
языка удобно использовать макросы. Компиляция с условиями (#if, #elif,
#ifdef), включения кода (#include), макросы (#define), конкатенация
строк по существу формируют дополнительный язык, не связанный
синтаксисом с основным языком программирования. Препроцессор в C/C++
является довольно примитивным макроязыком. Самое время сделать шаг
назад и посмотреть, для чего используется препроцессор, а затем
внедрить поддержку этих возможностей в собственно язык программирования;
Множественное наследование.
Это запутанная возможность сомнительной полезности. Множественное
наследование может быть заменено обычным наследованием с использованием
интерфейсов и агрегированием;
Пространства имен (namespace).
Пространства имен были попыткой решить проблему, возникающую при
объединении разработанных независимо друг от друга кусков кода, когда
пересекаются имена переменных, типов данных и так далее. Модульный
подход выглядит проще и удобнее для использования;
Файлы включения кода (include files).
Главной причиной медленной работы компиляторов заключается в том, что в
каждом модуле исходного кода необходимо обработать огромное количество
заголовочных файлов. Включение исходного кода целесообразнее
реализовать в виде импортирования таблицы символов;
Не виртуальные функции-члены классов.
В языке C++ разработчик класса должен наперед решить, виртуальной будет
функция-член или нет. Достаточно трудно отловить появившиеся ошибки,
когда разработчик забывает объявить в базовом классе виртуальной
функцию-член, которая переопределяется в производном классе. Более
гибким решением является автоматическое объявление всех функций-членов
классов виртуальными, а компилятор уже сам будет конвертировать функцию
в не виртуальную, если она не переопределяется в производных классах;
Битовые поля (bit fields) произвольного размера. Битовые поля сложны, неэффективны и достаточно редко используются;
Поддержка
16-битных компьютеров. В языке D нет никаких решений для генерации
качественного 16-битного кода, зато возможен плавный переход с
использования 32-битного плоского пространства памяти на 64-битную
архитектуру;
Взаимная зависимость проходов компилирования
(compiler passes). В языке C++, успешная обработка исходного кода
основывается на таблице символов (symbol table) и различных командах
препроцессора. Это делает невозможным предварительную обработку кода и
значительно усложняет работу анализаторов кода;
Различие между
операторами . и ->. В их различии нет необходимости, поскольку
оператор . в языке D служит также для разыменования указателей.
Перейдем к рассмотрению примеров на языке D (описание синтаксиса мы опустим, так как каждый, кто хоть немного знаком с C-подобными языками сразу же увидит родные конструкции).
Простой пример программы, печатающей параметры командной строки:
import std.stdio; // Таким образом в D подключаются библиотеки - прямо как в Java. Эта нужна для writefln() int main(char[][] args) //а вот так программа на D получает параметры ком. строки, C# не напоминает? { foreach(int i, char[] a; args) //тоже что-то из C# ))) writefln("args[%d] = '%s'", i, a); //замена printf в C++(аналог) return0; }
Даже из этого 7-строчного примера видно, насколько много языков ассимилировал в себе D.
Рассмотрим ещё один пример:
#!/usr/bin/dmd -run /* sh style script syntax is supported */
/* Hello World in D To compile: dmd hello.d or to optimize: dmd -O -inline -release hello.d */
// auto type inference and built-in foreach foreach (argc, argv; args) { // Object Oriented Programming
CmdLin cl = new CmdLin(argc, argv); // Improved typesafe printf writefln(cl.argnum, cl.suffix, " arg: %s", cl.argv); // Automatic or explicit memory management delete cl; }
// Nested structs and classes struct
specs { // all members automatically initialized int count, allocated; }
// Nested functions can refer to outer // variables like args specs argspecs() { specs* s = new specs; // no need for '->' s.count
= args.length; // get length of array with .length s.allocated = typeof(args).sizeof; // built-in native type properties foreach (argv; args) s.allocated += argv.length * typeof(argv[0]).sizeof; return *s; }
// built-in
string and common string operations writefln("argc = %d, " ~ "allocated = %d", argspecs().count, argspecs().allocated); }
class CmdLin { privateint _argc; privatechar[] _argv;