In Guard clauses (the when...
part after the destructuring section of a pattern match), we’re only allowed to use a very small subset of functions because these are the only ones that the BEAM can optimize and that are known to be pure (side-effect free).
One of the problems of this property of the BEAM, is that it becomes impossible to ‘nest’ guard clauses. In Elixir, we can write macros, allowing us to write short snippets in a guard clause that at compile-time expand to longer pieces of guard-safe functions. But great care needs to be taken to ensure that this macro does not include code that itself tries to pattern match or run guard clauses (or any other type of conditional branching for that matter) because the compiler does not allow this.
In Elixir, we have structs, which are a great type of abstraction to allow many different kinds of user-defined types and work with protocols on them. However, we cannot check properties of a struct inside a guard clause, because it is impossible to destructure a map inside a guard clause (there are no guard-safe functions that can do this).
However, it is possible to bind names to fields of your struct inside the destructuring part of the pattern match, and refer to these names inside the guard clause. But of course, this would mean hard-coding the pattern match every time I want to check if some property of a struct is true.
I think that it is possible to build an abstraction layer that allows this, though. After all, aren’t:
def foo(tuple) when elem(tuple, 0) == :ok do
# ...
end
and
def foo({42, _} = tuple) do
# ...
end
the same?
Therefore, why not write something like this:
def foo(%Box{}) when is_filled(box) do
# ...
end
and enhance the Elixir compiler so it will cleverly rewrite it to:
def foo(%Box{value: tmp0}) when tmp0 != nil do
# ...
end
?
I think that by doing this, we would be able to create a lot more possibilities for creating guard-safe macros. I believe that things like the arithmetic operators might finally be able to be made guard-safe as they could dispatch on structs then.
The only downside I can think of, is that it will make compilation a little more difficult.
What do you think? Interesting? Awesome? Horrible?