|
> - dynamic language ( this is the worst part ), working on large code base means problems ahead IMO, I the fact that Elixir is a dynamic language is not that much a problem thanks to pattern matching. Elixir's pattern matching is really powerful, allowing for things like: def move(_state, _x, _y, kind) when kind not in ~w(forward backwards) do
{:error, :invalid_move_kind}
end
def move(state, x, y, kind) do
get(state, x, y)
|> do_move(state, x, y, kind)
end
In this case, I am asserting that "kind" is either string "forward" or "backwards". If not, I return the an error :invalid_move_kind. I don't need to check if pos is nil or not string, since I can assert using pattern matching that everything with my inputs are right.Also, there are things like structs: defmodule RobotVsDinosaurs.Robot do
alias RobotVsDinosaurs.Robot
@enforce_keys [:pos]
defstruct name: nil, pos: nil
def set(state, x, y, robot = %Robot{}) do
case Matrix.elem(state, x, y) do
%Robot{} -> {:ok, Matrix.set(state, x, y, robot)}
_ -> {:error, :invalid_type}
end
end
end
What I am saying in the code above is that %Robot{} must have a :name and a :pos entries, and by default they're nil. However, to create a new %Robot{}, :pos must be different them nil. And of course, I can pattern match if my input is actually a %Robot{} and not a simply dict.You can also do crazy things like pattern matching if a byte array have some specific characteristics, like a magic number. So while I think it would be nice for Elixir to have types (there is Dialyzer however it is kinda a PITA to use), it is less necessary than Python/Ruby/Javascript thanks to the above. |