Created
July 28, 2017 07:34
-
-
Save h4cc/61f916295b806627088354345f7a0133 to your computer and use it in GitHub Desktop.
Example how matching on elixir structs will make code more robust and refactorable with less possible errors at runtime.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is our struct with some fields. | |
defmodule User do | |
defstruct name: "julius", role: :user | |
end | |
defmodule UserManager do | |
# Matching on %User{} will ensure we will get a user. | |
# Matching on %User{name: name} will make the elixir compiler check that there is a name in user at compile time. | |
# Using a guard for new_role will ensure the type of data in our struct, so its important too. | |
# Updating the user with %User{user|role: new_role} will also ensure that all given fields exist at compile time. | |
# Downside: Need to write more code ... | |
# Upside: Easier refactoring. No possible ways to have runtime errors | |
def promote(%User{name: name, role: role} = user, new_role) when is_atom(new_role) do | |
IO.puts "Promoting user #{inspect name} from #{inspect role} to #{inspect new_role}" | |
%User{user|role: new_role} | |
end | |
# user can be any kind of struct here, even a map. | |
# There is no check what type of data new_role is. | |
# Using user.name and user.role will be accessed at runtime and can fail. | |
# Updating the user without using the struct can fail at runtime too. | |
# Downside: Refactoring is hard. Runtime errors possible. | |
# Upside: Less code | |
def promoto_not_matched(user, new_role) do | |
IO.puts "Promoting user #{inspect user.name} from #{inspect user.role} to #{inspect new_role}" | |
%{user|role: new_role} | |
end | |
end | |
# Helper for running as script. | |
defmodule Main do | |
def main() do | |
user = %User{} | |
admin1 = UserManager.promote(user, :admin) | |
IO.inspect admin1 | |
admin2 = UserManager.promote(user, :admin) | |
IO.inspect admin2 | |
end | |
end | |
Main.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Don't ask me how I ended on a 7 years old gist. But here I am ๐ Day-3 on my Elixir learning curve.
I'm building a library to consume an external API I depend on. I know the structure of the responses.
/api/v1/categories
"should" always return something like:My first attempt was to use
Ecto
to parse the data I receive:It is working fine. But I wonder if I could get rid of one deps (
Ecto
) and use the tools of Elixir like defstruct. Based on your gist, this is what I ended up with:But the outcomes is not what I expected:
I'm don't understand why the pattern matching is not working ๐