back

by auraham·3y ago·view on hn ↗
When I started reading the post, I though the author would talk about pattern matching to get rid of the switch block. In that case, creating a user can be expressed in Elixir as follows:

    def createUser(attributes, "admin") do
        create(attributes) |> setupAdmin |> setupNotifications
    end

    def createUser(attributes, "customer") do
        create(attributes) |> setupCustomer |> setupNotifications
    end

    # example
    User.createUser(%{name: "laura", age: 30}, "admin")
Here, we chain functions using a pipe, |>, assuming that each function returns a user-like variable, like %User{}

I also liked the idea of using a callback for decoupling code (although that approach was discouraged by many users in this post). It could be done in Elixir as follows:

    def createUserCallback(attributes, callback) do
        create(attributes) |> callback.() |>  setupNotifications
    end

    # example
    User.createUserCallback(%{name: "laura", age: 30}, &User.setupCustomer/1)
    User.createUserCallback(%{name: "laura", age: 30}, &User.setupAdmin/1)
Since callback can be any kind of function, we can use pattern matching to enforce that the return type of each function is a user, ie %User{}:

    def createUserCallback(attributes, callback) do
        user = %User{} = create(attributes)
        user = %User{} = callback.(user)
        user = %User{} = setupNotifications(user)
        user
    end
Another approach is using a @spec annotation to define the signature of the callback.

Full code:

    defmodule User do
      defstruct name: nil, age: nil, type: nil

      defp create(_attributes = %{name: name, age: age}) do
        %User{name: name, age: age}
      end

      defp setupNotifications(user = %User{}) do
        IO.puts("User created #{user.type}: #{user.name}")
        user
      end

      def setupAdmin(user = %User{}) do
        %User{ user | type: "admin" }
      end

      def setupCustomer(user = %User{}) do
        %User{ user | type: "customer" }
      end

      def createUser(attributes, "admin") do
        create(attributes) |> setupAdmin |> setupNotifications
      end

      def createUser(attributes, "customer") do
        create(attributes) |> setupCustomer |> setupNotifications
      end

      def createUserCallback(attributes, callback) do
        user = %User{} = create(attributes)
        user = %User{} = callback.(user)
        user = %User{} = setupNotifications(user)
        user
      end
    end