Проверим на примере: пишем сервис с аэропортами и направлениями.
Пока что всё в порядке. Отлично, съели печеньку, смотрим, что дальше в джире. Список самых популярных направлений?
Для начала делаем небольшой тестовый список и получаем нечитаемую простыню:
Добавляем щепотку читаемости:
И получаем понятный аккуратный вывод:
Иногда при разработке нужно анализировать содержимое переменных. Внутреннее представление точное, но не всегда читаемое. В таких случаях можно научить Elixir переводить ваши структуры в строки. Для этого определите функцию
В качестве дополнительного бонуса автоматом начнёт работать интерполяция. Без реализации
На этом всё. Читаемого кода!
defmodule Airport do
defstruct [:id, :name]
end
defmodule Direction do
defstruct [:origin, :destination]
def example do
madrid = %Airport{id: "MAD", name: "Madrid"}
riga = %Airport{id: "RIX", name: "Riga"}
%Direction{origin: riga, destination: madrid}
end
end
Пока что всё в порядке. Отлично, съели печеньку, смотрим, что дальше в джире. Список самых популярных направлений?
Для начала делаем небольшой тестовый список и получаем нечитаемую простыню:
popular = Enum.map(1..5, fn _ -> Direction.example end)
# =>
# [%Direction{destination: %Airport{id: "MAD", name: "Madrid"},
# origin: %Airport{id: "RIX", name: "Riga"}},
# %Direction{destination: %Airport{id: "MAD", name: "Madrid"},
# origin: %Airport{id: "RIX", name: "Riga"}},
# %Direction{destination: %Airport{id: "MAD", name: "Madrid"},
# origin: %Airport{id: "RIX", name: "Riga"}},
# %Direction{destination: %Airport{id: "MAD", name: "Madrid"},
# origin: %Airport{id: "RIX", name: "Riga"}},
# %Direction{destination: %Airport{id: "MAD", name: "Madrid"},
# origin: %Airport{id: "RIX", name: "Riga"}}]
Добавляем щепотку читаемости:
defimpl String.Chars, for: Airport do
def to_string(airport) do
"#{airport.name} (#{airport.id})"
end
end
defimpl String.Chars, for: Direction do
def to_string(direction) do
"#{direction.origin} > #{direction.destination}"
end
end
И получаем понятный аккуратный вывод:
Enum.each(popular, fn(x) -> IO.puts(x) end)
# =>
# Riga (RIX) > Madrid (MAD)
# Riga (RIX) > Madrid (MAD)
# Riga (RIX) > Madrid (MAD)
# Riga (RIX) > Madrid (MAD)
# Riga (RIX) > Madrid (MAD)
А теперь серьёзно
Иногда при разработке нужно анализировать содержимое переменных. Внутреннее представление точное, но не всегда читаемое. В таких случаях можно научить Elixir переводить ваши структуры в строки. Для этого определите функцию
to_string
в рамках реализации протокола String.Chars
. В качестве дополнительного бонуса автоматом начнёт работать интерполяция. Без реализации
to_string
для аэропортов такое бы не сработало:"#{direction.origin} > #{direction.destination}"
На этом всё. Читаемого кода!
Поделиться с друзьями
begemot_sun
Спасибо. Меня, как Erlang разработчика, пугает в Elixir следующее:
1. Мы можем переопределить значение переменной: a = 1; a = 2; a;
2. В описании модуля нет списка экспортированных функций. Интерфейс модуля приходится ловить в самом коде.
3. Отсутсвие рекордов. Повальная мапизация не к добру.
4. Отсутствие вменяемого IDE. В этом пункте я говорю про IntelliJIDEA c её замечательным Erlang-плагином. Спасибо разработчикам этого плагина, большое спасибо. Но вот для Elixir там сырая поделка пока. Банально не могу прыгнуть к определению функции, модуля и т.п.
5. Повальное оберточное движение. Когда берут Erlang библиотеку, и надстраивают над ней некие интерфейсы, которые помогают сделать Elixir код красивее. Имхо, Хосе Валим уж лучше бы тогда Erlang модернизировал. Было бы как C++/C. Но не случилось.
6. Многословие. Всякие def do, и т.п. (но это на любителя, дело привычки).
7. Метапрограммирование на любителя. Позволяет делать очень много магического кода работающего по-умолчанию. Один программист написал, другой не смог поддерживать.
Мне нравится Elixir потому что:
1. Ну вообще супер стандартная библиотека. В Erlang этого не хватало.
2. Стандартизированные интерфейсы (протоколы). Этого тоже в Erlang не хватало.
В общем я люблю Elixir. Но пока не могу начать промышленно разрабатывать на нём.
Что касается Phoenix. В Erlang-рассылке мелькал такой ответ: https://groups.google.com/d/msg/erlang-russian/adw4gxqIDsk/REH04iEiDgAJ — вот прям моё мнение.
Буду рад найти единомышленников, а также заказчиков ;)
HedgeSky
2. Это верно. С другой стороны, если хочется видеть в начале модуля список экспортированных функций, можно организовать pre-commit hook, добавляющий этот список в качестве комментария.
3. В Elixir'е есть структуры. С одной стороны, это обёртка над map'ами. С другой стороны, с ними работает pattern-matching, позволяющий отделять структуры разных типов друг от друга. Например, в этой статье
%Airport{}
и%Direction{}
— структуры.4. Elixir — молодой язык, не везде всё работает из коробки. В плагине для Sublime Text тоже изначально не работал переход к определению функции/модуля, но я это исправил)
По поводу других пунктов: согласен с тем, что часть особенностей — на любителя. Но так во всём.
Ну а что касается Phoenix: монолитные фреймворки проще для использования. Рельсы популяризовали Ruby, дав возможность появиться комьюнити, которое стало создавать и модульные фреймворки (напр. Hanami).
Phoenix вполне может стать популяризатором Elixir'a: удобный в использовании, быстрый, многопоточный и масштабируемый.
begemot_sun
2. Есть что хочется видеть, а есть обязательные конструкции. По мне, хороший язык должен обеспечить читаемость кода из коробки. Ни я, ни кто-то другой не будут что-то делать дополнительное, если это требование не сформулировано языком. Всякие доп фишки, на то и доп. что опциональны. Выразительность языка — это мера выразительности самого хренового кода написанного на нём.
3. Структуры — это не рекорды, я говорил о нативных рекордах Ерланга. Да, это сахар. Но очень полезный. И так же работающий с матчингом.
HedgeSky
Кстати, я тут посмотрел, в Elixir'e есть поддержка records. А здесь Jose Valim рассказывает про Struct vs Record. Кратко: records лучше работают с проверкой типов dialyzer'ом (не обязательные конструкции) и в некоторых случаях немного быстрее. Взамен мы получаем полиморфизм и возможность матчить по содержимому структур.
P.S. спасибо, что упомянули records. Не знал, что в эликсире есть такой модуль, не сталкивался с его использованием.
begemot_sun
Спасибо и вам за ликбез, также не знал об этом.
JC_IIB
За 1, 2, 5, 6 прямо подпишусь. Впрочем, я в принципе не люблю этот синтаксический сахар к Erlang.
begemot_sun
На самом деле стдлиба в Еликсире меня впечатляет. В Ерланге этого не хватает, особенно всяких интерфейсов и т.п. которые изначально стандартизированы. В Ерланге можно написать все тоже самое, вот только чтобы внедрить это у все нужно ой как постараться.