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

История создания и развитие

Язык был разработан в 1980-х годах в лабораториях шведской телекоммуникационной компании Ericsson. Основными создателями выступают Джо Армстронг, Роберт Вирдинг и Майк Вильямс. Название языка, предположительно, является отсылкой к имени датского математика Агнера Крарупа Эрланга, чьи работы легли в основу теории массового обслуживания, активно применяемой в телекоммуникациях. Также существует версия, что название образовано от сокращения «Ericsson Language».

Официальный выпуск языка состоялся в 1992 году. На раннем этапе разработки колоссальное влияние на Erlang оказал язык логического программирования Пролог. Первоначальные версии Erlang функционировали на базе модифицированной виртуальной машины Пролога. Помимо этого, в архитектуре языка прослеживается влияние Лиспа, Ады, Модулы-2 и раннего функционального языка Миранда.

На протяжении 1990-х годов язык активно и успешно применялся внутри компании Ericsson для разработки программного обеспечения телефонных коммутаторов и сетевого оборудования. Однако в 1998 году руководство компании приняло стратегическое решение о переводе всех новых разработок на набирающий популярность язык Java. Чтобы сохранить Erlang и дать ему возможность развиваться, создатели приняли решение перевести его в статус проекта с открытым исходным кодом.

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

Парадигма и вычислительная модель

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

Главной архитектурной особенностью является реализация модели акторов для параллельных вычислений. В среде Erlang могут одновременно выполняться миллионы изолированных микропроцессов. Эти процессы не имеют общей разделяемой памяти, что полностью исключает классические проблемы параллельного программирования, такие как состояние гонки (race conditions).

Взаимодействие между процессами осуществляется исключительно посредством асинхронного обмена сообщениями. Каждый процесс обладает собственной очередью входящих сообщений. Процесс-отправитель не получает автоматического уведомления о доставке, поэтому ответственность за корректную архитектуру взаимодействия полностью ложится на разработчика. Процесс-получатель извлекает сообщения из очереди и обрабатывает их с помощью механизма сопоставления с образцом (pattern matching), определяя, как именно реагировать на ту или иную структуру данных.

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

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

Система типов данных

Язык обладает сильной динамической типизацией. Базовые типы данных включают в себя:

Числа: поддерживаются целые числа и числа с плавающей запятой.

Атомы: именованные константы, концепция которых напрямую заимствована из Пролога. Атомы используются преимущественно для идентификации и в операциях сравнения. Логические значения «истина» и «ложь» также реализованы в виде атомов.

Кортежи: составной тип данных с фиксированным количеством элементов любой природы. Разработчикам рекомендуется первым элементом кортежа всегда указывать атом-тег, описывающий назначение данных (например, для облегчения отладки). Синтаксической надстройкой над кортежами является концепция «записей» (record), позволяющая обращаться к элементам по именам.

Списки: структура данных переменной длины, концептуально разделенная на «голову» (первый элемент) и «хвост» (остальная часть списка), аналогично языку Лисп.

Строки: в Erlang отсутствует самостоятельный тип данных для работы с текстовыми строками. Текст, заключенный в двойные кавычки, воспринимается компилятором исключительно как список целых чисел, соответствующих кодам символов в таблице Unicode. Это означает, что к строкам применяются все стандартные функции обработки списков.

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

Битовые строки: используются для компактного хранения нетипизированных данных в памяти.

Специфические типы: ссылки, идентификаторы портов и идентификаторы процессов (PID), необходимые для маршрутизации сообщений в распределенной среде.

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

Синтаксис и структура программы

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

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

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

Концептуальный пример синтаксиса определения модуля и вызова функции с охранным выражением:

 -module(example).
 -export([process_data/1]).

 process_data(Value) when Value > 0 ->
     positive_result;
 process_data(Value) ->
     other_result.

Распределенные вычисления глубоко интегрированы в синтаксис языка. Базовой единицей распределенной среды является узел (работающий экземпляр виртуальной машины). Узлом может быть как отдельный процессор, так и целый кластер серверов. Для создания процесса на удаленном узле достаточно знать его идентификатор. Язык предоставляет встроенные средства для балансировки нагрузки и бесшовного добавления новых вычислительных узлов.

Для взаимодействия с внешним миром и другими языками программирования (C, Java, Python) предусмотрены специальные драйверы. Сторонние системы могут представляться для виртуальной машины Erlang как стандартные узлы сети, обменивающиеся с ней сообщениями.

Применение, преимущества и недостатки

Основная сфера применения языка сегодня — это телекоммуникации, облачные сервисы, базы данных, веб-фреймворки и высоконагруженные системы обмена сообщениями. На Erlang написаны серверные части таких платформ, как чат социальной сети Facebook и мессенджер WhatsApp. Кроме того, архитектура языка с его независимыми акторами-процессами идеально ложится на математические модели искусственных нейронных сетей, где каждый процесс имитирует работу отдельного нейрона.

К неоспоримым преимуществам языка относится высочайшая надежность и отказоустойчивость разрабатываемых систем. Функциональная природа и встроенная поддержка параллелизма позволяют создавать компактный код. В сравнении с языком C++ объем исходного кода на Erlang может быть на 80% меньше. По утверждениям некоторых исследований производительности, в узкоспециализированных задачах распределенной маршрутизации сообщений Erlang способен превосходить C++ по скорости выполнения до двух раз (на 100%). Исходный код языка полностью открыт и доступен на платформе GitHub, вокруг него сформировалась полноценная экосистема стандартных библиотек (модули для математики, массивов, работы с календарем, а также отдельная библиотека для графики).

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

См. также

Euphoria (язык программирования) F#

Смотреть видео