Consider the following if statement
to check if a variable should be type casted.
foo = "123"
foo = if is_integer(foo) do
Integer.to_string(foo)
end
if it is not an integer, foo
will be nil
, so to prevent this from happening, I have to do
foo = "123"
foo = if is_integer(foo) do
Integer.to_string(foo)
else
foo
end
I found myself doing this pattern a lot from time to time, is there a better way to express this pattern?
1 Like
Probably matching in the header and delegating after conversion is the most correct.
But otherwise in this specific case you can just replace the whole if
thing with just foo = to_string(foo)
.
1 Like
To me, if you have to do this a lot inside your code, it is a sign that your code can be improved.
Your internal representation of your data should be clear and unambiguous. This avoids heaps of bugs and reduces code.
In general you should do all type validation and conversion when things enter your system (from external source, from APIs if you are writing a library). Then from there on you should trust the types are correct otherwise I’d recommend that you just use let it crash.
For APIs I usually function guards I’d do something like
def my_fun(x) when is_integer(x), do: Integer.to_string(x)
def my_fun(x), do: x
7 Likes
And do it fast?
i.e.
# file: demo.ex
defmodule Demo do
def stringify(value) when is_integer(value) do
Integer.to_string(value)
end
def stringify(value) when is_binary(value) do
cond do
String.valid?(value) ->
value
true ->
raise ArgumentError, message: "cannot stringify value #{inspect value}"
end
end
end
iex(1)> c("demo.ex")
[Demo]
iex(2)> Demo.stringify(123)
"123"
iex(3)> Demo.stringify("123")
"123"
iex(4)> Demo.stringify(<<239, 191, 19>>)
** (ArgumentError) cannot stringify value <<239, 191, 19>>
demo.ex:12: Demo.stringify/1
iex(4)> Demo.stringify(:some_atom)
** (FunctionClauseError) no function clause matching in Demo.stringify/1
The following arguments were given to Demo.stringify/1:
# 1
:some_atom
demo.ex:4: Demo.stringify/1
iex(4)>
2 Likes
You could also use a combination of and
(or &&
) and ||
, as in this example:
foo = is_integer(foo) and Integer.to_string(foo) || foo
3 Likes