rrmartins
Control flow structures vs Pattern Matching
Hello,
I came to make a provocation about a way of writing code.
I’m writing a small private project to shorten urls and I came across a change in the writing of a case.
I saw that when writing the case in my function I felt that the function seemed complex to understand and read. I thought about changing the case to use Pattern Matching of the functions.
leaving this code:
defp validate_url(changeset, field, opts \\ []) do
validate_change(changeset, field, fn _, value ->
case URI.parse(value) do
%URI{scheme: nil} ->
"is missing a scheme (e.g. https)"
%URI{host: nil} ->
"is missing a host"
%URI{host: host} ->
case :inet.gethostbyname(Kernel.to_charlist(host)) do
{:ok, _} -> nil
{:error, _} -> "invalid host"
end
end
|> case do
error when is_binary(error) -> [{field, Keyword.get(opts, :message, error)}]
_ -> []
end
end)
end
for this:
defp validate_url(changeset, field, opts \\ []) do
validate_change(changeset, field, fn _, value ->
value
|> URI.parse()
|> handle_parse()
|> handle_error_parse()
end)
end
defp handle_error_parse(error) when is_binary(error), do: [{field, Keyword.get(opts, :message, error)}]
defp handle_error_parse(_), do: []
defp handle_parse(%URI{scheme: nil}), do: "is missing a scheme (e.g. https)"
defp handle_parse(%URI{host: nil}), do: "is missing a host"
defp handle_parse(%URI{host: host}) do
host
|> Kernel.to_charlist()
|> :inet.gethostbyname()
|> handle_hostbyname()
end
defp handle_hostbyname({:ok, _}), do: nil
defp handle_hostbyname({:error, _}), do: "invalid host"
I’m preferring to use Pattern Matching instead of case and other control flow structures.
what do you think?
Most Liked
stefanchrobot
I personally prefer case over multiple function heads (sidenote: both use pattern matching!). But I’d do this:
defp validate_url_field(changeset, field, opts \\ []) do
validate_change(changeset, field, fn _, value ->
case validate_url(value) do
:ok -> []
{:error, message} -> [{field, Keyword.get(opts, :message, message)}]
end
end)
end
defp validate_url(string) do
case URI.parse(string) do
%URI{scheme: nil} ->
{:error, "is missing a scheme (e.g. https)"}
%URI{host: nil} ->
{:error, "is missing a host"}
%URI{host: host} ->
case :inet.gethostbyname(Kernel.to_charlist(host)) do
{:ok, _} -> :ok
{:error, _} -> {:error, "invalid host"}
end
end
end
sodapopcan
This is one of those cases of “Which do you prefer?” Your answer to that is the right one ![]()
Personally I prefer multi-head functions whenever it’s possible, but that’s just me. I maybe wouldn’t start every function name with handle_ as it feels a bit noisy but, again, that’s just me.
sodapopcan
PS, pattern matching essentially is control flow (among other things). It’s right there on the Erlang homepage ![]()
Last Post!
cjbottaro
I am on the fence on this one. Sometimes I think the code is cleaner looking with a single function head that has a single case statement… ![]()
Especially if the function has other heads that deal with other things. Sometimes the combinatory explosion flatting is just too much.
Popular in Discussions
Other popular topics
Chat & Discussions>Discussions
Latest on Elixir Forum
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









