D (язык программирования)

Материал из Seo Wiki - Поисковая Оптимизация и Программирование

Перейти к: навигация, поиск
D
Семантика:

мультипарадигменный: императивное, объектно-ориентированное, обобщённое программирование

Тип исполнения:

компилятор

Появился в:

1999 г.

Автор(ы):

Уолтер Брайт

Последняя версия:

1.056

Тестовая версия:

2.040

Типизация данных:

строгая, статическая

Основные реализации:

Digital Mars D, LDC

Испытал влияние:

Си, C++, Lua, C#

D — язык программирования общего назначения, предназначенный для прикладного и системного программирования. Он является языком высокого уровня, но сохраняет возможности прямого взаимодействия с программным интерфейсом операционной системы и с оборудованием. D предназначен для написания средних и крупных систем с миллионами строк исходного кода, для ведения командной разработки. Язык D имеет C-подобный синтаксис, он лёгок в изучении, поддерживает многие возможности в помощь программисту, а также пригоден для проведения агрессивной оптимизации кода компилятором.

Стабильная версия 1.0 вышла 2 января 2007[1]. Экспериментальная версия 2.0 выпущена 17 июня 2007 года.[2]

Стабильная версия 1.0 работает на Windows, Linux, Mac OS, а с версии 1.043 также и на FreeBSD. Так же с недавнего времени стали доступны исходные коды DMD (официальная реализация компилятора от Digital Mars).

Содержание

Основные особенности D

Возможности, унаследованные от C++

Синтаксис языка D схож с синтаксисом C++, что облегчает его изучение людям, знакомым с С++, а также перенос исходного кода с С++.

Для D не существует виртуальной машины. Программы, написанные на D, компилируются в объектные файлы, которые затем могут быть объединены линковщиком в исполняемый файл. Стандартные инструменты для разработки на С++ (например make) могут быть использованы для D.

Чего нет в языке D

  • Совместимость с исходным кодом на языке C. Уже существуют языки программирования, совместимые с исходным кодом, написанным на языке C (C++ и ObjectiveC). Дальнейшая работа в этом направлении препятствует реализации существенных возможностей.
  • Препроцессор. Для расширения языка удобно использовать макросы. Условная компиляция (#if, #elif, #ifdef), включение файлов кода (#include), макросы (#define), конкатенация строк, по существу формируют дополнительный язык, не связанный синтаксисом с основным языком программирования (макроязыком).
  • Множественное наследование. Однако это компенсируется интерфейсами, работа с которыми поддерживается языком D.
  • Пространства имён (namespaces). Пространства имён были попыткой решить проблему, возникающую при объединении разработанных независимо друг от друга кусков кода, когда пересекаются имена переменных, типов данных и так далее. Модульный подход выглядит проще и удобнее для использования.
  • Битовые поля (bit fields) произвольного размера. Битовые поля сложны, неэффективны и достаточно редко используются[источник не указан 1970 дней].
  • Поддержка 16-битных компьютеров. В языке D нет никаких решений для генерирования качественного 16-битного кода.
  • Взаимная зависимость проходов компилирования (compiler passes). В языке C++ успешная обработка исходного кода основывается на таблице символов (symbol table) и различных командах препроцессора. Это делает невозможным предварительную обработку кода и значительно усложняет работу анализаторов кода.
  • Оператор разыменования с обращением к члену класса ->. В языке D оператор обращения к члену класса производит разыменование по умолчанию при необходимости.

Для чего предназначен язык D

  • Использование анализаторов кода[источник не указан 1970 дней];
  • Компиляция с максимальным количеством включенных уровней предупреждений (warning levels)[источник не указан 1970 дней];
  • Упрощение ООП C++;
  • Автоматическое управление памятью;
  • Встроенное тестирование и верификация[источник не указан 1970 дней];
  • Написание крупных приложений;
  • Абстрактная работа с указателями[источник не указан 1970 дней];
  • Программирование математики. Язык D поддерживает работу с комплексными числами и операторами определения NaN’ов (not a number) и бесконечностей (infinity). Они были добавлены в стандарт C99, но не были добавлены в C++.

Для чего D не предназначен

  • Для уже существующих программ.
  • Скриптового программирования.
  • В качестве первого языка программирования.

Особенности языка D

Объектно-ориентированное программирование

Классы

Объектно-ориентированная природа языка D происходит от классов. Модель наследования не поддерживает наследования от нескольких классов, зато расширяется за счет использования интерфейсов. На вершине иерархии наследования находится класс Object, от которого все классы наследуют базовый набор функциональности. Экземпляры классов работают по ссылке, поэтому после обработки исключений не требуется писать сложный код для очистки памяти.

Перегрузка операторов

Классы могут быть приспособлены для работы с уже существующими операторами. Благодаря перегрузке операторов можно создавать новые типы данных. Например, можно создать тип данных для работы с большими числами, создав класс и перегрузив операторы +, -, * и /, чтобы использовать алгебраические операции с этими числами.

Эффективность

Модули

Файлы исходного кода взаимно однозначно соответствуют модулям. Вместо включения (#include) файлов исходного кода достаточно импортировать модуль. В этом случае нет необходимости беспокоиться о том, что один и тот же модуль будет импортирован несколько раз, а, значит, и нет необходимости обрамлять код в заголовочных файлах с использованием макросов препроцессора #ifndef/#endif или #pragma once.

Объявление против описания

C++ обычно требует, чтобы функции и классы были объявлены дважды — объявление происходит в заголовочных файлах (*.h), а описание происходит в файлах исходного кода (*.cpp). Это утомительный и подверженный ошибкам процесс. Очевидно, что программисту достаточно объявить функцию или класс лишь однажды, а компилятор должен впоследствии извлечь информацию об объявлении и сделать ее доступной для импортирования. Именно так работает язык программирования D, например:

class ABC
{
    int func() { return 7; }
    static int z = 7;
};
 
int q;

И более нет необходимости отдельного описания функций-членов, атрибутов и спецификаций внешних объявлений (extern), как в языке C++:

int ABC::func() { return 7; }
 
int ABC::z = 7;
 
extern int q;

Заметка: Конечно же, в C++ тривиальные функции вроде { return 7; } тоже описаны внутри класса, но более сложные должны быть описаны отдельно. Вдобавок, если нужны опережающие ссылки (ссылки на класс или функцию, которые объявлены, но ещё не определены), то для этих объектов нужны прототипы (prototype). Следующий код не будет работать в C++:

class Foo
{
    int foo(Bar *c) { return c->bar(); }
};
 
class Bar
{
    public:
        int bar() { return 3; }
};

Но эквивалентный код на языке D будет рабочим:

class Foo
{
    int foo(Bar c) { return c.bar; }
}
 
class Bar
{
    int bar() { return 3; }
}

А то, будет ли функция встраиваемой (при компиляции вызов такой функции заменяется ее кодом) или нет, в языке D зависит от настроек оптимизатора.

Шаблоны

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

Ассоциативные массивы

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

Настоящий typedef

В языках C и C++ оператор typedef на самом деле просто создает синоним типа данных и никакого нового типа данных не объявляется. В языке D оператор typedef объявляет новый тип данных. Таким образом, код

typedef int handle;

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

int foo(int i);
int foo(handle h);

Документация

Документирование традиционно происходит в два этапа — написание комментариев, описывающих, что делают функции, а затем перенос этих комментариев вручную в отдельные HTML-файлы и файлы документации man. И, естественно, со временем, то, что описывается в документации, будет отличаться от того, что на самом деле происходит в исходном коде. Возможность генерации документации напрямую из комментариев в файлах исходного кода не только экономит время при подготовке документации, но и облегчает поддержку соответствия документации исходному коду. Для языка D существует единая спецификация для генератора документации.

Для генерации документации в языке C++ существуют инструментальные средства, разработанные третьими лицами. Использование этих инструментальных средств имеет ряд недостатков:

  • Очень сложно обработать C++ код на 100 % правильно, для этого на самом деле потребуется компилятор. Инструменты от третьих лиц (third party tools) корректно работают только с подмножеством языка C++.
  • Разные компиляторы поддерживают разные версии языка C++ и разные расширения языка. Очень трудно соответствовать всем этим вариациям поддержки языка C++.
  • Инструменты для генерирования документации из C++ могут не быть реализованы для некоторых платформ или могут не соответствовать последней версии компилятора.

Будучи встроенным в компилятор, генерирование документации является единой для всех реализаций языка D.

Функции

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

Вложенные функции

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

Функциональные литералы (function literals)

Анонимные функции могут быть встроены напрямую в выражение.

Динамические делегирования (closure)

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

Спецификаторы доступа к параметрам функций: in, out и inout

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

Все эти возможности D позволяют использовать больше различных программных интерфейсов, а также избавляет от необходимости использовать различные искусственные приемы, как, например IDL (Interface Definition Languages).

Массивы

Массивы в языке C имеют несколько недостатков, которые приходится корректировать:

  • Информация о размерности массива не прилагается к массиву, поэтому должна извлекаться дополнительно и передаваться отдельно. Классический пример — это объявление функции main(int argc, char *argv[]). В языке D, функция main объявляется так: main(char[][] args);
  • Когда массив передается в функцию, на самом деле передается ссылка на него, даже когда прототип функции говорит, что должен быть передан массив. Когда происходит это преобразование, вся информация о типе массива теряется;
  • Размерность массивов языка C не может быть изменена. Это означает, что даже такая простая структура данных, как стек, должна быть реализована в виде сложного класса;
  • В языке C нельзя произвести проверку на нарушение границ массива, просто потому, что размерность массива неизвестна;
  • Массивы объявляются с использованием оператора [] после названия массива. Это ведет к использованию очень неуклюжего синтаксиса при объявлении, скажем, ссылки (указателя - в терминах C) на массив:
int (*array)[3];

В языке D оператор [] при объявлении массива ставится после типа данных:

int[3]* array; // объявляется ссылка на массив из трёх целых чисел
long[] func(int x); // объявляется функция, возвращающая массив длинных целых

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

Строки

Манипулирование строками является стандартным средством при программировании, поэтому поддержка строк должна быть встроена в язык программирования. В языках C и C++ работа со строками выглядит неуклюже. Современные языки поддерживают конкатенацию, копирование и другие операции со строками. Поддержка строк ведет к облегчению работы с массивами строк.

Управление ресурсами (resource management)

Автоматическое управление памятью

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

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

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

Конечно, сбор мусора можно использовать и в C++, но этот язык не дружественен по отношению к сборщикам мусора, что не может не сказаться на эффективности сбора мусора.

Явное управление памятью

Несмотря на то, что язык D поддерживает автоматический сбор мусора, операторы new и delete могут быть перегружены для определенных классов.

RAII

RAII — это современная методика разработки для управления распределением и освобождением ресурсов. Язык D поддерживает методику RAII в контролируемой и предсказуемой манере, независимой от цикла сбора мусора.

Производительность

Легковесные составные типы данных

Язык D поддерживает простые структуры в стиле языка C не только для совместимости с этим языком, но и потому что они очень полезны в тех случаях, когда возможностей классов слишком много.

Встроенный ассемблер

Драйвера устройств, высокопроизводительные системные приложения, а также встраиваемые системы (embedded systems) требуют углубления до уровня команд ассемблера. Программирование на языке D не требует использования ассемблера, но он реализован и является частью языка.

Надёжность

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

Отладочный код

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

Обработка исключений

Модель try-catch-finally предпочтительнее, чем просто try-catch, потому что не требует создания временных (dummy) объектов, деструктор которого будет выполнять то, что может сделать finally.

Синхронизация

Многопоточное программирование становится всё более распространенным, поэтому в языке D реализованы базовые возможности для создания многопоточных приложений. Синхронизация может быть применена ко всему объекту или к отдельным его методам.

synchronized int func() { ... }

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

Устойчивые к ошибкам методики

  • Динамические массивы вместо указателей;
  • Переменные-ссылки вместо указателей;
  • Ссылки на объекты вместо указателей;
  • Сбор мусора вместо явного управления памятью;
  • Встроенные возможности синхронизации потоков;
  • Встраиваемые функции вместо макросов;
  • Уменьшение необходимости использовать указатели;
  • Явные размеры целого типа данных;
  • Отсутствие неопределенности, касающейся наличия знака у символьного типа;
  • Отсутствие необходимости повторного объявления;

Проверки во время компиляции

  • Более строгая проверка на соответствие типа данных;
  • Никаких пустых условий в цикле for;
  • Присвоения не возвращают булевого значения;
  • Проверка использования устаревших API;

Проверки во время выполнения

  • Выражения assert();
  • Проверка на выход за пределы массива;
  • Исключение при нехватке памяти;

Совместимость

Приоритеты операторов и правила вычисления

Язык D сохранил операторы из языка C, а также их приоритеты и правила вычисления. Это позволит избежать ситуаций, когда операторы ведут себя неожиданным образом.

Прямой доступ к API языка C

Язык D не только имеет типы данных, соответствующие типам данных языка C, но и обеспечивает прямой доступ к функциям языка C. В таком случае нет необходимости писать функции-обертки (wrapper functions) или копировать значения членов составных типов по одному.

Поддержка всех типов данных языка C

Это делает возможным взаимодействие с API языка C или с кодом существующей библиотеки языка C. Эта поддержка включает структуры, объединения, перечисления, указатели и все типы данных, введённые в стандарте C99.

Обработка исключений операционной системы

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

Использование существующих инструментариев

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

Управление проектом

Контроль версий

В языке D реализована встроенная поддержка генерирования нескольких версий программ из одного исходного кода. Это заменяет использование команд препроцессора #if и #endif.

Устаревание

Код со временем изменяется, поэтому старый код со временем заменяется новым, улучшенным. Старая версия кода должна быть доступна для обратной совместимости, но может быть отмечена как не рекомендованная к использованию (deprecated). Это облегчает работу команды поддержки по определению зависимостей от устаревшего кода.

Отсутствие предупреждений (warnings)

Компиляторы языка D не генерируют предупреждений при встрече неоднозначного кода. Код может быть понятным компилятору или непонятным, это избавляет от необходимости решать, какие предупреждения относятся к ошибкам программы, а какие — нет. Использование предупреждений компилятора является признаком плохого дизайна языка.[источник не указан 1960 дней]

Отсутствие макросов

Отказ создателей языка от препроцессора (как например в языке Cи) многие расценивают как рискованный и неверный шаг. Но в Ди имеются встроенные средства, которые позволяют обходиться без препроцессора.

Реализация на языке Си Реализация на языке D
#if !defined(SOME_FILE_H)
//#ifndef SOME_FILE_H
#define SOME_FILE_H
// Код
#endif
// Объявление постоянной
#define MAX_INT 32767
 
// Создание псевдонимов
#define true TRUE
 
#if defined(Mac OS X)
// Код для Mac
#endif
// Объявление постоянной
const uint MAX_INT=32767
 
// Создание псевдонимов
alias TRUE true
 
version(Mac OS X)
{
    // Код для Mac
} else {
    // Иначе
}

Стандартная библиотека

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

Существование двух разных стандартных библиотек создаёт некоторые трудности. Для написания кода, работающего под обеими библиотеками можно использовать следующую конструкцию:

version (Tango)
{
    // Код работающий с функциями Tango
} else
{
    // Код работающий с функциями Phobos
}

Tangobos

Для того чтобы решить проблемы с библиотеками был запущен проект Tangobos. Tangobos — обёртка Tango, дающая программисту интерфейс Phobos.

Примеры

Эта программа печатает аргументы командной строки. Функция main является точкой входа программы, а args — массив с параметрами запуска программы.

module main; // Желательно объявлять
 
version (Tango)
    import tango.io.Stdout;
else
    import std.stdio; // для writefln()
 
void main(char[][] args)
{
    foreach(int i, char[] a; args)
    {
        version(Tango)
            Stdout.formatln("args[{}] = {}", i, a);
        else
            writefln("args[%d] = '%s'", i, a);
    }
}

См. также

Примечания

Ссылки

  • D Programming Language (англ.) (4 мая 2006). — официальный сайт. Проверено 28 июля 2008.
bg:D (език за програмиране)

ca:Llenguatge D cs:D (programovací jazyk) de:D (Programmiersprache) en:D (programming language) eo:D (programlingvo) es:Lenguaje de programación D fa:زبان برنامه‌نویسی دی fi:D (ohjelmointikieli) fr:D (langage) gl:Linguaxe de programación D hu:D programozási nyelv id:D (bahasa pemrograman) it:D (linguaggio) ja:D言語 ka:D (პროგრამირების ენა) ko:D (프로그래밍 언어) ms:Bahasa pengaturcaraan D nl:D (programmeertaal) no:D (programmeringsspråk) pl:D (język programowania) pt:D (linguagem de programação) sk:D (programovací jazyk) sv:D (programspråk) tr:D programlama dili zh:D語言

Личные инструменты

Served in 0.999 secs.