Проверим на примере: пишем сервис с аэропортами и направлениями.

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}"

На этом всё. Читаемого кода!
Поделиться с друзьями
-->

Комментарии (7)


  1. begemot_sun
    17.05.2017 20:11
    +1

    Спасибо. Меня, как 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 — вот прям моё мнение.

    Буду рад найти единомышленников, а также заказчиков ;)


    1. HedgeSky
      17.05.2017 21:21

      2. Это верно. С другой стороны, если хочется видеть в начале модуля список экспортированных функций, можно организовать pre-commit hook, добавляющий этот список в качестве комментария.
      3. В Elixir'е есть структуры. С одной стороны, это обёртка над map'ами. С другой стороны, с ними работает pattern-matching, позволяющий отделять структуры разных типов друг от друга. Например, в этой статье %Airport{} и %Direction{} — структуры.
      4. Elixir — молодой язык, не везде всё работает из коробки. В плагине для Sublime Text тоже изначально не работал переход к определению функции/модуля, но я это исправил)

      По поводу других пунктов: согласен с тем, что часть особенностей — на любителя. Но так во всём.

      Ну а что касается Phoenix: монолитные фреймворки проще для использования. Рельсы популяризовали Ruby, дав возможность появиться комьюнити, которое стало создавать и модульные фреймворки (напр. Hanami).
      Phoenix вполне может стать популяризатором Elixir'a: удобный в использовании, быстрый, многопоточный и масштабируемый.


      1. begemot_sun
        17.05.2017 22:27

        2. Есть что хочется видеть, а есть обязательные конструкции. По мне, хороший язык должен обеспечить читаемость кода из коробки. Ни я, ни кто-то другой не будут что-то делать дополнительное, если это требование не сформулировано языком. Всякие доп фишки, на то и доп. что опциональны. Выразительность языка — это мера выразительности самого хренового кода написанного на нём.
        3. Структуры — это не рекорды, я говорил о нативных рекордах Ерланга. Да, это сахар. Но очень полезный. И так же работающий с матчингом.


        1. HedgeSky
          17.05.2017 23:32

          Кстати, я тут посмотрел, в Elixir'e есть поддержка records. А здесь Jose Valim рассказывает про Struct vs Record. Кратко: records лучше работают с проверкой типов dialyzer'ом (не обязательные конструкции) и в некоторых случаях немного быстрее. Взамен мы получаем полиморфизм и возможность матчить по содержимому структур.
          P.S. спасибо, что упомянули records. Не знал, что в эликсире есть такой модуль, не сталкивался с его использованием.


          1. begemot_sun
            18.05.2017 12:24

            Спасибо и вам за ликбез, также не знал об этом.


    1. JC_IIB
      18.05.2017 06:31

      За 1, 2, 5, 6 прямо подпишусь. Впрочем, я в принципе не люблю этот синтаксический сахар к Erlang.


      1. begemot_sun
        18.05.2017 12:30

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