Interested Article - D (язык программирования)
- 2021-02-01
- 1
D ( Ди ) — мультипарадигмальный статически типизированный компилируемый язык программирования , созданный Уолтером Брайтом из компании . Начиная с 2006 года соавтором также является Андрей Александреску . D является потомком языка C++ , но существенно доработан по сравнению с ним. Также он заимствует ряд концепций из языков программирования Python , Ruby , C# , Java , Eiffel .
D доступен для операционных систем Windows, Linux, macOS, FreeBSD. Ведётся работа по портированию на Android .
История
В предисловии к книге А. Александреску «Язык программирования D» Уолтер Брайт пишет, что начал разработку этого языка в 1999 году. Проект задумывался как реинжиниринг языка C++ с целью избавиться от наиболее существенных недостатков исходного языка и внедрить в него современные архитектурные решения. При создании языка D была сделана попытка соединить производительность компилируемых языков программирования с безопасностью и выразительностью динамических .
Первоначально автор предполагал назвать язык «Mars», но из-за преемственности по отношению к C++ в обсуждениях язык постоянно называли «D», в результате именно это название и закрепилось за проектом.
Стабильная версия компилятора 1.0 вышла 2 января 2007 . Вскоре после выхода компилятора 17 июня 2007 года автор перевёл версию 1 в режим поддержки и приступил к разработке версии 2.0, которая изначально не гарантировала обратной совместимости . Эта версия (последняя на сегодняшний день мажорная версия D) развивается и по сей день.
Обзор языка
В языке D реализовано множество синтаксических средств и концепций, отсутствующих в C++: контрактное программирование , встроенные юнит-тесты , модули вместо заголовочных файлов (до C++ 20), поддержка сборки мусора (при сохранении доступности ручного управления памятью), встроенные ассоциативные массивы, замыкания , анонимные функции , значительно переработан механизм шаблонов.
Синтаксис
D относится к семейству C-подобных языков, в общих чертах его синтаксис похож на C/C++/C#, Java. При разработке языка соблюдается принцип: код, одинаково валидный и в C, и в D, должен вести себя одинаково.
« Hello, world! » на D:
import std.stdio;
void main()
{
writeln ("Hello, world!");
}
Так же, как в C, функция
main()
является точкой входа.
Конструкции
if
,
for
,
while
,
do-while
выглядят и работают аналогично C/C++. Инструкция множественного выбора
switch
выглядит аналогично C++, но допускает переменные в метках ветвей
case
и требует, чтобы каждая ветвь
case
завершалась
break
или
return
; для перехода на следующую ветвь после обработки текущей необходимо использовать специальную конструкцию
goto case
. Также запрещены конструкции
switch
без ветви
default
.
Из дополнительных управляющих конструкций можно отметить
static if
— инструкцию для условной компиляции (условие проверяется статически и в код включается содержимое той ветви, которая ему соответствует), оператор полного множественного выбора
final switch
— в отличие от обычного
switch
, он работает только со значениями
enum
, а компилятор статически проверяет, что в выборе учтены все возможные варианты и выдаёт ошибку в противном случае. Также есть цикл по коллекции
foreach
.
Модульность
В D встроена система разбиения программы на модули (пакеты), обеспечивающая раздельную компиляцию и контролируемый импорт-экспорт. Система пакетов напоминает принятую в Java или Go: пакеты образуют иерархическую структуру, естественно отображаемую на дерево файловой системы. В отличие от C++, в D нет глобального пространства имён, каждое имя определяется в каком-либо пакете. С помощью инструкции
import
модуль программы может импортировать пакет, сделав доступными все имеющиеся в нём определения. Обращение к импортированным именам может выполняться с квалификацией: «
имя_пакета.имя_объекта
».
Язык предусматривает ряд средств, направленных на обеспечение удобной работы с импортируемыми именами. Есть возможность переименования пакета при импорте, задания альтернативного имени (алиаса) импортируемого пакета, импорта конкретных имён. Кроме того, язык разрешает без каких-либо дополнительных инструкций использовать импортированные имена без квалификации именем пакета. Однако действует ограничение: если в области видимости есть более одного подходящего определения встреченного в программе имени, то компилятор выдаёт ошибку и требует, чтобы имя было явно квалифицировано. Это предотвращает так называемый «угон имён», когда при добавлении в списки импорта нового пакета компилятор начинает связывать некоторое имя в программе не с тем определением, с которым оно связывалось ранее.
Универсальный синтаксис вызова функций (UFCS)
В D реализован механизм UFCS (Uniform function call syntax), позволяющий вызывать функции для любого объекта так, как будто они являются его методами. Например:
import std.stdio;
import std.algorithm;
import std.array;
void main()
{
auto a = [2, 4, 1, 3];
// все три следующих варианта корректны и работают одинаково
writeln(a); // "классический" C-подобный вариант
a.writeln(); // функция вызывается так, как будто является методом объекта "a", хотя и не является таковой
a.writeln; // функцию без параметров можно вызывать без скобок
// это позволяет использовать цепочки вызовов, характерные для функциональных языков
int[] e = a.sort().reverse;
// многострочная цепочка вызовов также возможна
stdin
.byLine(KeepTerminator.yes)
.map!(a => a.idup)
.array
.sort;
}
Атрибуты функций
Функции в D могут быть определены с дополнительными необязательными атрибутами, которые позволяют явно указывать некоторые аспекты поведения этих функций. Например, функция, помеченная атрибутом pure , гарантированно является функционально чистой (с некоторыми оговорками) . Функциональная чистота при этом проверяется на этапе компиляции. Пример объявления функции с атрибутом:
pure int sum (int first, int second)
{
return first + second;
}
int sum (int first, int second) pure // атрибуты можно указывать и после списка аргументов
{
return first + second;
}
Примеры атрибутов функций:
- pure — функциональная чистота
- @safe — гарантия безопасной работы с памятью
- nothrow — функция гарантированно не генерирует исключений
- @nogc — гарантия того, что функция не содержит операций, выделяющих память на сборщике мусора
- @property — атрибут метода класса, позволяющий избежать использования «наивных» геттеров-сеттеров
Параллельные вычисления
В язык встроен механизм запуска параллельных подпроцессов с помощью встроенной функции
spawn()
и обмена данными между параллельно исполняемыми фрагментами кода путём передачи сообщений (функции
send()
и
receive()
/
receiveTimeout()
). Использование обмена сообщениями считается авторами D предпочтительнее обмена данными через общую память.
Тем не менее, в случаях, когда это необходимо (например, при передаче между сопрограммами больших объёмов данных) имеется возможность применять традиционный для императивных языков подход с разделяемыми областями памяти и синхронизацией доступа через семафоры и мьютексы . Для поддержки такого обмена:
-
c помощью модификатора
shared
могут объявляться данные, разделяемые между потоками, при этом на уровне компилятора блокируются попытки работать с этими данными не-атомарными операциями; - библиотека языка предоставляет стандартные синхронизационные примитивы;
- библиотека языка предоставляет специальные блокировочные классы, которые используются для контекстной блокировки : объявление экземпляра такого класса в методе синхронизирует код от данной точки до конца метода;
- с помощью модификатора synchronized можно объявить целый класс синхронизированным : все методы этого класса компилятор автоматически синхронизирует, так что никакие два из них не могут выполняться параллельно для одного и того же экземпляра класса, объявленного как shared.
Для всех встроенных средств синхронизации компилятор автоматически отслеживает и запрещает попытки изменять внутри синхронизируемого кода неразделяемые данные, доступные более чем одному потоку.
Встроенные юнит-тесты
В D юнит-тесты являются частью языка, их можно использовать без подключения дополнительных библиотек или фреймворков.
import std.stdio;
int first (int[] arr) {
return arr[0];
}
unittest {
int[] arr1 = [1, 2, 3];
int[] arr2 = [10, 15, 20];
assert(first(arr1) == 1);
assert(first(arr2) == 10);
}
void main() {
// ...
}
Парадигмы программирования
D реализует пять основных парадигм программирования — императивное , ООП , метапрограммирование , функциональное программирование и параллельные вычисления ( модель акторов ).
Управление памятью
D использует сборщик мусора для управления памятью, однако возможно и ручное управление с помощью перегрузки операторов
new
и
delete
, а также с помощью
malloc и free
, аналогично C. Сборщик мусора можно включать и выключать вручную, можно добавлять и удалять области памяти из его видимости, принудительно запускать частичный или полный процесс сборки. Существует подробное
, описывающее различные схемы управления памятью в D для тех случаев, когда стандартный сборщик мусора неприменим.
SafeD
SafeD — название подмножества языка D, использование которого гарантирует безопасность доступа к памяти .
Типы данных
Язык имеет богатый набор определённых типов данных и средств для определения новых типов. Типы в языке D разделяются на типы-значения и типы-ссылки.
Базовые типы
Набор базовых типов можно разделить на следующие категории :
-
void
— специальный тип для пустых значений -
bool
— логический тип -
целочисленные типы: знаковые
byte
,short
,int
,long
и соответствующие им беззнаковыеubyte
,ushort
,uint
,ulong
-
типы для чисел с плавающей точкой:
float
,double
,real
. Для типов с плавающей точкой есть соответствующие им варианты для мнимых и комплексных чисел:-
мнимые:
ifloat
,idouble
,ireal
-
комплексные:
сfloat
,сdouble
,сreal
-
мнимые:
-
знаковые (символьные) типы:
char
,wchar
,dchar
, обозначающие кодовые единицы кодировок UTF-8, UTF-16 и UTF-32 соответственно.
В отличие от C++ все размеры целочисленных типов определены спецификацией. То есть, тип int будет всегда размером 32 бита. Целочисленные литералы можно записывать в десятичной, двоичной (с префиксом 0b) и шестнадцатеричной (с префиксом 0x) системе счисления. Способ записи литералов в восьмеричной системе в стиле C (то есть с префиксом 0) был убран, так как такую запись легко спутать с десятичной. Если всё-таки нужно использовать восьмеричную систему, можно воспользоваться шаблоном std.conv.octal .
Производные типы
-
pointer
— указатель -
array
— массив -
associative array
— ассоциативный массив -
function
— функция -
delegate
— делегат -
string
,wstring
,dstring
— удобные псевдонимы для неизменяемых массивов знаковых (символьных) типовimmutable(char)[]
,immutable(wchar)[]
иimmutable(dchar)[]
, обозначающие неизменяемые (квалификатор immutable ) строки Юникода в одной из кодировок UTF-8, UTF-16 и UTF-32 соответственно.
Пользовательские типы
-
alias
— псевдоним -
enum
— перечисление -
struct
— структура -
union
— объединение -
class
— класс
Вывод типов, ключевые слова «auto», «typeof» и безымянные («Voldemort») типы
В D реализован механизм вывода типов. Это значит, что тип, как правило, может быть вычислен на этапе компиляции и его не обязательно указывать явно. Например, выражение:
auto myVar = 10
на этапе компиляции будет преобразовано в
int myVar = 10
.
Использование вывода типов дает несколько преимуществ:
- Более лаконичный и читаемый код, особенно если в нём используются длинные имена структур или классов. Например, выражение
VeryLongTypeName var = VeryLongTypeName(/* ... */);
может быть заменено на
auto var = VeryLongTypeName(/* ... */);
- с помощью ключевого слова typeof можно создать переменную такого же типа, как у существующей переменной, даже если её тип неизвестен. Пример:
// file1.d
int var1;
// file2.d
typeof(var1) var2; // var2 получает тип int
- использование безымянных типов. Пример:
// Функция фактически возвращает результат типа TheUnnameable, но, поскольку этот тип определен внутри функции,
// мы не можем явно задать его как тип возвращаемого значения.
// Тем не менее, мы можем задать возвращаемый тип как "auto", предоставив компилятору вычислить его самостоятельно
auto createVoldemortType(int value)
{
struct TheUnnameable
{
int getValue() { return value; }
}
return TheUnnameable();
}
Безымянные типы неофициально называются Voldemort-типы по аналогии с Воланом-де-Мортом («Тот-Кого-Нельзя-Называть»), главным антагонистом серии о Гарри Поттере . Вывод типов не следует путать с динамической типизацией , поскольку хотя тип не задается явно, вычисляется он на этапе компиляции, а не во время выполнения.
Реализации
- — Digital Mars D ( ), эталонный компилятор, разрабатываемый Уолтером Брайтом. Этот компилятор наиболее полно реализует стандарт языка, поддержка всех нововведений появляется в нём в первую очередь. Фронт-энд и бэк-энд ( ) распространяются под лицензией Boost .
- — DMD ( ) — фронт-энд для LLVM ( )
- — DMD ( ) — фронт-энд для компилятора GCC
- — LDC-based toolkit for cross-compiling to iOS
- (недоступная ссылка) — Toolkit for cross-compiling to Android (x86 using DMD and ARM using LDC)
- — экспериментальный компилятор (компилятор как библиотека), использующий LLVM в качестве бэк-энда и не основанный на DMD.
- — LDC fork which provides direct Clang interoperability, allowing the use of C headers directly.
- — DMD fork which outputs C source code instead of object files
- — DMD fork which outputs JavaScript source code instead of object files
- D Compiler for .NET — A back-end for the D programming language 2.0 compiler . It compiles the code to Common Intermediate Language (CIL) bytecode rather than to machine code. The CIL can then be run via a Common Language Infrastructure (CLR) virtual machine .
- DIL is a hand-crafted compiler implementation for the D programming language written in D v2 using the standard library. The lexer and the parser are fully implemented. Semantic analysis is being worked on. The backend will most probably be .
Инструменты и средства разработки
IDE и редакторы
Поддержка D в , реализованная с помощью плагинов:
IDE | Плагин | Платформы |
---|---|---|
IntelliJ IDEA | кроссплатформенный | |
Eclipse | кроссплатформенный | |
MonoDevelop / Xamarin | кроссплатформенный | |
Visual Studio | Windows | |
Visual Studio Code | кроссплатформенный | |
XCode | Mac OS X | |
Zeus IDE | Windows |
Нативные IDE для языка D:
- (Windows, Linux)
- (Windows, Linux, OS X) — среда создана на самом D, поддерживает подсветку синтаксиса, автозавершение кода, DUB, различные компиляторы, отладку и многое другое.
D поддерживается текстовых редакторов: Vim, Emacs, Kate, Notepad++, Sublime Text, TextMate и других .
Менеджер пакетов
DUB — официальный менеджер пакетов D. DUB выполняет функции репозитория пакетов и используется для управления зависимостями, а также в качестве системы сборки. Набор зависимостей, метаданные о проекте и флаги компилятора хранятся в формате JSON или SDL. Пример простого файла проекта (JSON):
{
"name": "myproject",
"description": "A little web service of mine.",
"authors": ["Peter Parker"],
"homepage": "http://myproject.example.com",
"license": "GPL-2.0",
"dependencies": {
"vibe-d": "~>0.7.23"
}
}
Утилиты и инструменты
rdmd — утилита, идущая в комплекте с компилятором DMD, позволяющая компилировать и запускать файлы с исходным кодом D «на лету». Это позволяет использовать D для небольших программ аналогично bash, perl и python:
// myprog.d
#!/usr/bin/env rdmd
import std.stdio;
void main()
{
writeln("Hello, world with automated script running!");
}
Вызов команды
./myprog.d
в консоли автоматически скомпилирует и выполнит программу.
DPaste — онлайн-сервис для запуска программ на D в браузере, похожий на сервисы JSBin и CodePen .
run.dlang.io — онлайн-компилятор и дизассемблер.
Использование, распространение
Распространение языка D ограничено, но он применяется для реальной промышленной разработки ПО. На официальном сайте приводится список из 26 компаний, успешно использующих D в разработке программных систем, работающих в самых различных сферах, включая системное программирование, веб-проекты, игры и игровые движки, ПО для научных расчётов, утилиты различного назначения и прочее. Продвижением языка D занимается, в частности D Language Foundation — общественная организация, пропагандирующая сам язык D и открытое программное обеспечение , созданное с его использованием.
Согласно индексу TIOBE , максимальный интерес к D проявлялся в 2007—2009 годах, в марте 2009 года индекс языка D достиг 1,8 (12-е место), что является для него абсолютным максимумом. После снижения в первой половине 2010-х, к 2016 году он пришёл в относительно стабильное состояние — численное значение индекса колеблется в диапазоне 1,0-1,4, в рейтинге язык находится в третьей десятке. В , составленном по результатам агрегации данных о вакансиях разработчиков, язык D не входит ни в основной (top-20), ни в общий (top-43) список, что говорит о невысокой востребованности у работодателей.
Примеры кода
Пример 1
« Hello, world! »
import std.stdio;
void main() {
writeln("Hello, world!");
}
Пример 2
Программа, которая выводит аргументы командной строки, с которыми была вызвана
import std.stdio: writefln;
void main(string[] args)
{
foreach (i, arg; args)
writefln("args[%d] = '%s'", i, arg);
}
Пример 3
Программа, которая построчно считывает список слов из файла и выводит все слова, которые являются анаграммами других слов
import std.stdio, std.algorithm, std.range, std.string;
void main()
{
dstring[][dstring] signs2words;
foreach(dchar[] w; lines(File("words.txt")))
{
w = w.chomp().toLower();
immutable key = w.dup.sort().release().idup;
signs2words[key] ~= w.idup;
}
foreach (words; signs2words)
{
if (words.length > 1)
{
writefln(words.join(" "));
}
}
}
См. также
- Сравнение возможностей D с другими языками см. в статье
Примечания
- . 3 января 2014 года.
- . из оригинала 6 февраля 2023 . Дата обращения: 6 февраля 2023 .
- . Дата обращения: 7 июня 2015. 21 мая 2015 года.
- от 5 марта 2007 на Wayback Machine (англ.)
- . Дата обращения: 11 января 2009. Архивировано из 1 июня 2012 года. (англ.)
- . Дата обращения: 17 июня 2015. 17 июня 2015 года.
- . Дата обращения: 7 июня 2015. 17 мая 2015 года.
- . Дата обращения: 8 июня 2015. 19 июня 2015 года.
- . CodePlex Archive. Дата обращения: 16 февраля 2018. 26 января 2018 года.
- . InfoQ. Дата обращения: 16 февраля 2018. 30 ноября 2018 года.
- . Дата обращения: 16 июня 2015. 3 июля 2015 года.
- . Дата обращения: 16 июня 2015. Архивировано из 6 июля 2015 года.
- . Дата обращения: 23 сентября 2019. 24 декабря 2019 года.
- . dlang.org. Дата обращения: 7 октября 2019. 6 августа 2019 года.
Литература
- Александреску А. Язык программирования D = The D Programming Language. — , 2012. — 544 с. — ISBN 978-5-93286-205-6 .
- Язык программирования D —
- Programming in D —
Ссылки
- (англ.) . — официальный сайт. Дата обращения: 10 мая 2012. Архивировано из 18 мая 2012 года.
- .
- (англ.) . — репозиторий пакетов для D и сайт официального менеджера пакетов DUB.
- (14 марта 2013). Архивировано из 15 марта 2013 года.
- (англ.) . — свободное программное обеспечение на/для языка D. Дата обращения: 8 января 2006. Архивировано из 18 мая 2012 года.
- (англ.) (27 мая 2007). — Язык программирования D для GCC . Дата обращения: 17 июля 2011.
- (англ.) . — Язык программирования D для LLVM . Архивировано из 18 мая 2012 года.
- Александреску, Андрей (англ.) (15 июня 2009). Дата обращения: 7 января 2011. Архивировано из 18 мая 2012 года.
,
- 2021-02-01
- 1