Pull to refresh

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

Reading time 5 min
Views 42K
Доброго всем времени суток!
Возникло желание (и даже возможность!) рассказать сообществу о замечательном языке программирования D. Как ни печально, в сети по нему все еще минимум информации, а на хабре и того меньше.
Все скорее всего о нем даже знают, но мало кто пытался писать на нем проекты, а все из за того, что он, видите ли, «не выстрелил», что у него нет будущего. Основная задумка, с которой я пишу эту статью — развеять некоторые заблуждения по поводу этого, несомненно, замечательного языка программирования, ну и заодно, конечно, просто отдать в широкие массы еще немного информации о нем.

О чем же пойдет речь?

Да, первым делом я не хочу писать «почтовый сервер в 200 строк кода», как делают любители хаскелла. Это, несомненно, демонстрирует мощь языка, но не это цель данной статьи.

А буду я следовать задумке авторов языка, и косвенно пропагандировать его, как замену (или аналог) C++ — как язык, в котором если возможности для всего, и как достойный конкурент других современных языков.

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

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

Первым делом я хотел бы показать, что язык D поддерживает все эти стили, при чем совершенно естественным образом (рискуя нарваться на неодобрение: гораздо более естественно, чем C++), что этот язык буквально — для всех.*

Для начала немного общих сведений:

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

Ничего кардинально нового (ну почти, но не будем вдаваться) в языке нет, главное его преимущество — удобство для всех.** Что это значит? Это значит, что язык комбинирует мощь и выразительность (а соответственно и так же уменьшает время разработки) языков типа Java и C#, но не теряет прямой связи с системой на уровне C ( и скорость скомпилированного кода!).
Это значит, что почти каждый программист, привыкший писать приложения на языке %langname% сможет легко и непринужденно приспособиться к D, даже не сменив свой стиль программирования!***
Ну, это все реклама, перейдем к конкретике.

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

Ну, тут вряд ли можно придумать что-то оригинальное, так что вот не очень осмысленная, но все же функция:

int inc(int a)
{
	return a+1;
}



Приятным добавлением по сравнению с C++ являются вложенные функции (в этом месте программисты на паскале торжествуют):

int incTwice(int a)
{
	int inc(int a)
	{
		return a+1;
	}
	return inc(inc(a));
}



Очень удобно для инкапсуляции, не так ли?
Это, наверное, все, что можно сказать о процедурном стиле, перейдем дальше — к более интересному.

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

int main()
{
	auto inc = (int a) {return a+1;};
	writeln(inc(1));
}



Для любопытных, вот обьявления без автоматического вывода типа:

int function(int) inc = function (int a) {return a+1;};



Более того, в D можно создавать делегаты — функции, поддерживающие замыкания.

int c = 1;
int delegate(int) inc = delegate (int a) {return a+c;};



Функциями и делегатами легко манипулировать, они очень прозрачны и код не зашумлен из за вывода типов.
В принципе, по моим ощущениям D не менее функциональный, чем Python, хоть и не дотянет до haskell-а.

В добавок упомяну еще одну функциональную «фишку»: pure functions. Посмотрим:

pure int inc(int a)
{
	return a+1;
}



Это значит, что функция чистая, то есть не содержит и не изменяет состояния, как своего, так и системы в целом и для одинаковых аргументов даст одинаковые значения.

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

Отмечу, что он так же следит за корректностью. Не получится сделать вот так:

int c = 1;
pure int inc(int a)
{
	return a+c;	// ошибка, программист не прочитал определение чистой функции.
}



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

class A
{
	int v;
	int inc(int a)
	{
		return a+1;
	}
}



Даже возможность их наследовать никого не удивит!

class B : A
{
	int v;
	override int inc(int a)
	{
		return a+2;		// trollface
	}
}



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

Добавлю, что в языке нет множественного наследования классов, только множественное наследование интерфейсов.
Так же в языке есть хитрость: множественное наследование классов можно симулировать, не нарушая древовидную структуру графа родственных связей классов. Для тех, кто заинтересовался, не буду раскрывать интригу — читайте книгу Александреску «The D programming language».****

Это очень забавная и, в то же время, удобная особенность.

Что я еще обещал? Ах да, прототипное наследование.

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

Однако, тут такое тоже возможно (простите уж за много строк, но сами знаете, что ООП-код получается немного жирным):

class A
{
	string s;
	this() { s = ""; }		// да, так называются конструкторы, по-моему удобней, чем по названию класса.
	this(string s)
	{
		this.s = s;
	}
	override string toString()	// перегрузим метод корневого класса Object
	{
		return s;
	}

}

A createA(string s)
{
	class B : A		// точно, вложенные в функцию классы!
	{
		this() { s = ""; }	
		this(string s)	// конструкторы не наследуются.
		{
			this.s = s;
		}
		override string toString() { return "trollface"; }
	}
	return new B(s);
}

void main()
{
	A a = new A("hi!");
	A b = createA("hi!");
	writeln(a, " : ", b);		// ну да, выведет "hi! : trollface"
	readln();
}



Более того, для ленивых и любителей прекрасного есть анонимные классы, перепишем кусок кода:

A createA(string s)
{
	return new class A		// это значит, что наследуется от A
	{
		this() { s = ""; }
		this(string s) {this.s = s;}
		override string toString() { return "trollface"; }
	};
}



Итак, все анонсированные концепции программирования поддерживаются языком D, и при том вполне лаконично.
Конечно, этого не достаточно, чтобы язык стал хорошим. Чтобы он стал по-настоящему мощным и удобным, необходимо красивое и элегантное взаимодействие всех этих концепций.

Было бы неплохо, например, чтобы программист на javascript и программист на C++ могли писать один проект на D вдвоем, писать так, как привыкли в своей области, или, хотя бы, приближаться к этому, и при этом так, чтобы не терялась ни читабельность ни эффективность, и что еще важнее, чтобы оба стиля могли органично и без костылей взаимодействовать друг с другом.

Но это уже тема для другой статьи.

Я сам только изучаю этот замечательный язык, так что:

Во-первых, если тут найдутся гуру, которые найдут ошибки — с радостью выслушаю указания.

Во-вторых, я не собираюсь останавливаться на достигнутом, и, если сообщество заинтересуется, с удовольствием буду продолжать писать статьи о D по мере его изучения.

В-третьих, если возникнут вопросы, то с радостью готов ответить, обсудить и подискутировать, только без фанатизма.

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

* для многих.
** да-да, поймали — опять для многих.
*** И код при этом не станет откровенным говнокодом — каким он становится при переходе, например, от C++ к haskell (это я о себе :), а вполне вписывается в общий стиль языка.
**** А вы действительно думали, что название статьи я сам придумал?

P.S.
Как мне намекнули в комментариях, в Python все-таки есть замыкания. Видимо, давно я его пробовал, либо что-то изменилось, либо я просто забывчив. Приношу свои извинения.
Tags:
Hubs:
+53
Comments 65
Comments Comments 65

Articles