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

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 00:00, 9 июня 2016.
D
Спроектировано Walter Bright, Andrei Alexandrescu (c 2006)
Печать дисциплины строгая, статическая, с выводом типов
Портал: http://dlang.org/
Главная реализация
Digital Mars D (эталонная реализация), LDC, GDC

D (произносится [ diː ]) — мультипарадигмальный компилируемый язык программирования, созданный Уолтером Брайтом из компании Digital Mars. Начиная с 2006 г. соавтором также является Андрей Александреску. Изначально D был задуман как реинжиниринг языка C++, однако, несмотря на значительное влияние С++, не является его вариантом. Также язык испытал влияние концепций из языков программирования Python, Ruby, C#, Java, Eiffel.

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

Стабильная версия компилятора 1.0 вышла 2 января 2007.

Стабильная версия компилятора 2.0 (последняя на сегодняшний день мажорная версия) выпущена 17 июня 2007 года.

D доступен для операционных систем Windows, Linux, Mac OS, FreeBSD. Ведётся работа по портированию на Android.

Обзор языка

Синтаксис

D относится к семейству C-подобных языков с фигурными скобками, в общих чертах его синтаксис похож на C/C++/C#, Java. При разработке языка соблюдается принцип: код, одинаково валидный и в C, и в D, должен вести себя одинаково.

"Hello, world!" на D:

import std.stdio;

void main() {
    writeln ("Hello, world!");
}

Также как в C, функция main() является точкой входа.

Универсальный синтаксис вызова функций (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 - атрибут метода класса, позволяющий избежать использования "наивных" геттеров-сеттеров

Встроенные юнит-тесты

В 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() {
    // ...
}

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

Парадигмы программирования

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-типы по аналогии с Воланом-де-Мортом («Тот-Кого-Нельзя-Называть»), главным антагонистом серии о Гарри Поттере. Вывод типов не следует путать с динамической типизацией, поскольку хотя тип не задается явно, вычисляется он на этапе компиляции, а не во время выполнения.

Реализации

  • DMD — Digital Mars D, эталонный компилятор, разрабатываемый Уолтером Брайтом. Этот компилятор наиболее полно реализует стандарт языка, поддержка всех нововведений появляется в нём в первую очередь. Фронт-энд распространяется под лицензией [[Boost Software License|Boost]], бэк-энд - под проприетарной лицензией с доступом к исходным кодам. Часть кода бэк-энда была разработана в Symantec, и не может быть перелицензирована.
  • GDC — DMD-Фронт-энд для компилятора GCC.
  • LDC — DMD-Фронт-энд для LLVM
  • SDC — Экспериментальный компилятор (компилятор как библиотека), использующий LLVM в качестве бэк-энда и не основанный на DMD.

Инструменты и средства разрабоки

IDE и редакторы

Поддержка D в различных IDE, реализованная с помощью плагинов:

IDE Плагин Платформы
Eclipse DDT кроссплатформенный
MonoDevelop / Xamarin Mono-D кроссплатформенный
Visual Studio Visual-D Windows
XCode D for Xcode Mac OS X
Zeus IDE D for Zeus IDE Windows

Нативная IDE для языка D - Coedit (Windows, Linux)

D поддерживается во множестве текстовых редакторов: Vim, Emacs, Kate, Notepad++, Sublime Text, TextMate и других.

Менеджер пакетов

DUB - официальный менеджер пакетов D. DUB выполняет функции репозитория пакетов и используется для управления зависимостями, а также в качестве системы сборки. Набор зависимостей, метаданные о проекте и флаги компилятора хранятся в формате 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

rdmd — утилита, идущая в комплекте с компилятором DMD, позволяющая компилировать и запускать файлы с исходным кодом D «на лету». Это позволяет использовать D для небольших программ аналогично bash и perl:

// myprog.d

#!/usr/bin/env rdmd
import std.stdio;
void main()
{
    writeln("Hello, world with automated script running!");
}

Вызов команды ./myprog.dв консоли автоматически скомпилирует и выполнит программу.

DPaste

Dpaste - онлайн-сервис для запуска программ на D в браузере, похожий на сервисы JSBin и Codepen.

asm.dlang.org

asm.dlang.org - онлайн-компилятор и дизассемблер

Примеры кода

Пример 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(" "));
        }
    }
}

Ссылки

Хабрахабр

Официальный сайт