Не так давно я решил изменить образ мышления с помощью изучения нового языка программирования. С самого начала карьеры я работал с Джавой, и сейчас стал ощущать необходимость в совершенно другой парадигме. Так я повстречал невероятный язык под названием Эликсир. Рубистам хорошо знакомо название этого языка, а также, возможно, имя создателя – Джозе Валима. Однако у пришедших из более многословных языков шансы быть знакомыми с Эликсиром довольно низки. Так я решил написать несколько постов, чтобы помочь джавистам быстрее понять как устроен Эликсир. С помощью сравнения этих двух языков будет проще постичь новый для вас мир. Через эти посты я расскажу о синтаксисе, о работе языка и о ключевых особенностях, которые делают Эликсир по-настоящему потрясающим! На минутку забудем об объектах, классах и интерфейсах. Эликсир – компилируемый функциональный язык программирования, в основе которого лежит принцип иммутабельности. Достаточно запомнить три простых правила, чтобы понять, как же в нём всё устроено. Какой бы язык вы ни изучали, начало всегда одно – «Hello world!». Что ж, и мы не будем изобретать велосипед. Типы переменных в Эликсире определяются динамически во время выполнения программы. То есть нет необходимости явно задавать тип переменной при её объявлении, но при этом существуют определённые правила для каждого типа: А теперь создадим список и добавим в него новый элемент. Вот так это будет выглядеть на Джаве: Вспоминаем про первое правило – правило иммутабельности. Чтобы изменить значение какой-либо переменной, нужно заново привязать его к другой переменной. В примере ниже только первые три строчки изменяют значение элементов списка, далее уже создаётся копия с новыми значениями: Небольшая подсказка по спискам в Эликсире: они хранятся в памяти как связные списки. Так как имеется только ссылка на голову списка, то чтобы добавить в список новый элемент, нужно вставить его в начало, заменив голову списка. Это гарантирует выполнение вставки за время O(1). Если же требуется добавить элементы в конец, то нужно, как показано выше, произвести сцепление текущего списка с новым элементом, обёрнутым в список. Но с этим поаккуратнее, операция не из простых, поскольку требует большое количество памяти для копирования целого списка и создания нового. Ещё одна загадка – определение длины списка. Как вы могли догадаться, единственный способ это сделать – пройти весь список и посчитать количество элементов (сложность O(n)). Опять же, будьте осторожны. Не переживайте, просто ваш разум привык видеть всё в императивном ключе. Кроме этого способа подсчёта элементов есть и другие, которые будут рассмотрены позже. А пока… давайте прислушаемся к слогану небезысвестной компании: В отличие от методов в Джаве, которые могут иметь один из четырёх модификаторов доступа (public, default, protected или private), функции в Эликсире могут быть только двух типов (public или private). Определение публичных и приватных функций начинается со слов def и defp соответственно. Например: Итак, функцию можно задавать различными способами, при этом не нужно указывать ключевое слово return. А всё потому, что при обращении к функции будет всегда возвращён результат последней команды внутри неё. Попробуем снова добавить в список новый элемент, используя вышеприведённые функции. Поскольку в Джаве каждый объект является указателем, то при передаче объекта методу в качестве аргумента внутри метода используется созданная копия этого указателя. Это означает, что до тех пор пока значения списка не будут переприсвоены в addElement, любые изменения, происходящие в списке, будут отображены за пределами метода. В Эликсире всё совершенно иначе. Помните второе правило? Функции идемпотентны! Всё, что происходит внутри функций, за исключением возвращаемого результата, остаётся там же. Это одна из основных особенностей Эликсира, позволяющая запускать код изолированно и достигать тем самым абсолютно новый уровень параллелизма. И вам даже не придётся беспокоиться о побочных эффектах своего кода. Нельзя не упомянуть пайп-оператор |>. С его помощью можно легко и просто объединять функции в цепочки, передавая результат предыдущей функции следующей в качестве аргумента. Приведу простейший пример его использования: Чтобы реализовать что-то в Джаве, сначала нужно создать класс, содержащий конструкторы, методы и переменные. В Эликсире же код состоит из модулей, объединяющих функции в одно целое. Выглядит всё это примерно так: Можно провести параллель между модулями и функциями и статическими методами внутри класса. Здесь нет понятия экземпляра, поэтому каждый модуль и каждая функция «статичны». Различия в их использовании иллюстрирует следующий пример: Если вас заинтересовал язык, то подписывайтесь на рассылку, начиная с понедельника будет неделя всего самого интересного – от всеобъемлющей информационной поддержки новичков до вакансий и опенсорса для искушенных разработчиков. Спасибо за внимание! Переводчик