Добавление to_string упрощает разработку и дебаг кода на 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}"
    

    На этом всё. Читаемого кода!
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 7
    • +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 — вот прям моё мнение.

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

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

        Ну а что касается Phoenix: монолитные фреймворки проще для использования. Рельсы популяризовали Ruby, дав возможность появиться комьюнити, которое стало создавать и модульные фреймворки (напр. Hanami).
        Phoenix вполне может стать популяризатором Elixir'a: удобный в использовании, быстрый, многопоточный и масштабируемый.
        • 0
          2. Есть что хочется видеть, а есть обязательные конструкции. По мне, хороший язык должен обеспечить читаемость кода из коробки. Ни я, ни кто-то другой не будут что-то делать дополнительное, если это требование не сформулировано языком. Всякие доп фишки, на то и доп. что опциональны. Выразительность языка — это мера выразительности самого хренового кода написанного на нём.
          3. Структуры — это не рекорды, я говорил о нативных рекордах Ерланга. Да, это сахар. Но очень полезный. И так же работающий с матчингом.

          • 0
            Кстати, я тут посмотрел, в Elixir'e есть поддержка records. А здесь José Valim рассказывает про Struct vs Record. Кратко: records лучше работают с проверкой типов dialyzer'ом (не обязательные конструкции) и в некоторых случаях немного быстрее. Взамен мы получаем полиморфизм и возможность матчить по содержимому структур.
            P.S. спасибо, что упомянули records. Не знал, что в эликсире есть такой модуль, не сталкивался с его использованием.
            • 0
              Спасибо и вам за ликбез, также не знал об этом.
        • 0
          За 1, 2, 5, 6 прямо подпишусь. Впрочем, я в принципе не люблю этот синтаксический сахар к Erlang.
          • 0
            На самом деле стдлиба в Еликсире меня впечатляет. В Ерланге этого не хватает, особенно всяких интерфейсов и т.п. которые изначально стандартизированы. В Ерланге можно написать все тоже самое, вот только чтобы внедрить это у все нужно ой как постараться.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.