Rukenshia
Best Practice to get rid of if...else blocks?
I am used to early returns using the “return” keyword many languages provide.
As I am currently trying to learn elixir, I found it really hard to get a proper structure in my code and avoid if…else blocks which I have to nest very deep.
As an example, I wrote a small bot for Discord (don’t do it by the way, the discord_ex library doesn’t seem to work properly) and have to check several things when I receive a message.
As an example, here is one handler.
defp handle_command({ "msg", "remove-trigger", cmd }, { payload, state }) do
if payload.data["author"]["id"] == 1234 do
shortname = String.split(cmd, " ") |> List.first
if !Messages.has shortname do
send_message "unknown Message", { payload, state }
else
info = Messages.get(shortname)
trigger = String.replace_leading(cmd, "#{shortname} ", "")
if Enum.member?(info[:trigger], trigger) do
Messages.remove_trigger shortname, trigger
save_messages
end
send_message "trigger #{trigger} removed from #{shortname}", {payload, state}
end
end
end
I am pretty sure that this can be way improved - what’s the proper design pattern for that in Elixir, how do I escape the if-block hell?
Most Liked
josevalim
To add to this, at some point the community, even Elixir codebase, settled on do_send_message as a convention but today we see it as a bad practice. We are trying our best to not use do_ prefixes in Elixir and use proper function names for them, even if it ends up being the original name with extra information, for example, check_shortname_and_send_message.
atimberlake
You can pattern match the handle_command function to drop the first if
defp handle_command({"msg", "remove-trigger", cmd}, {%{data: %{"author" => %{"id" => 1234}}}, state}) do
# handle author 1234
end
defp handle_command({"msg", "remove-trigger", cmd}, {payload, state}) do
# No-op because you have no else
end
For the second if I would drop the call to Message.has/1 (assuming Message.get/1 returns nil for no message)
shortname = String.split(cmd, " ") |> List.first
do_send_message(Messages.get(shortname))
Then have a function deal with the presence or lack of message
defp do_send_message(nil) do
send_message "unknown Message", {payload, state}
end
defp do_send_message(info) do
trigger = …
end
Keep going by creating functions that handle each situation and try to come up with names that reveal the intent of each step (do_send_message is a terrible function name but because naming is hard, you get to solve that
)
Rukenshia
Thanks a lot guys, this really helped me. It’s really easy for me to forget how powerful the pattern matching just is. I know Rust’s pattern matching which is pretty cool already, but this is way more powerful.
Popular in Questions
Other popular topics
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
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









