Let’s say I have a Plug (the question is not limited to Plugs of course) where call/2 takes conn, processes it conditionally and returns it (processed or not) in the end. Now what would be more “correct”/idomatic approach:
def call(conn, _) do
if(some_condition) do
[...]
do_important_stuff(conn)
else
conn
end
end
or
def call(conn, _) do
conn = if(some_conditions) do
[...]
do_important_stuff(conn)
end
conn
end
Yeah, correct, thanks - it was written “out of head”, not an example of actual code. It’s more about “how does one write this kind of constructs in idiomatic Elixir”
I am also getting used to this being not so kosher - exactly the reason for opening this thread :-))
Coming from other languages I usually try to avoid unnecessary functions/methods calls as they can be far more expensive than an if. How is that in Elixir? I mean not in a trivial example like here, where I assume it’d be negligible either way. But in general? Especially in some tight loops of many iterations? Is this somehow optimised by the compiler/VM?
if may be getting a bad rep from imperative languages as it’s rarely an expression there, so using it in Elixir might feel a bit weird initially.
I think that if is a good fit for situations where you branch-off based on a boolean or truthy/falsy condition (no destructuring is involved). Have a look at this piece of code from the standard lib:
defp do_normalize(left..right//step, state) do
left = do_normalize(left, state)
right = do_normalize(right, state)
meta = meta_line(state)
if step == 1 do
{:.., meta, [left, right]}
else
step = do_normalize(step, state)
{:"..//", meta, [left, right, step]}
end
end
I think that using case here would not convey the intentions as well as if does. Writing a separate function just to match the step in the head would seem like adding needless noise.
if is a macro, so there’s no runtime penalty for using it.
For an Elixir-newbie (or better: pattern-matching-newbie) I think its the best to avoid if completely. Later (eg when commiting to stdlib) you can use it again.
It gives you empty list on nil. One place I use it often (in fact right after I posted the comment) is in Enum.flat_map, much cleaner than doing like enum.map then enum.filter
Another place is in building a single option keyword.