A possibility for extending the usability guard clauses

It’d not be ‘that’ hard to do all things considered. The elixir parser would just need to be made aware of matching contexts and call the macros over the whole context instead of just the part it is defined in, I did an experiment with this with my (highly incomplete, do not have time to work on it currently, busy at work) defguard experimentation:

# Defining
defmodule StructEx do
  import Defguard
  defguard is_struct(%{__struct__: struct_name}) when is_atom(struct_name)
  defguard is_struct(%{__struct__: struct_name}, substruct_name) when is_atom(struct_name) and struct_name === substruct_name
  defguard is_exception(%{__struct__: struct_name, __exception__: true}) when is_atom(struct_name)
end


# Using
defmodule Testering do
  use Defguard
  import StructEx

  def blah(any_struct) when is_struct(any_struct), do: 2
  def blah(_), do: 0

  def blorp(exc) when is_exception(exc), do: "exceptioned"
  def blorp(val), do: "No-exception:  #{inspect val}"
end


# Testing
assert Testering.blah(%{__struct__: Blorp}) === 2
assert Testering.blah(42) === 0
assert Testering.blorp(%ArithmeticError{}) === "exceptioned"
assert Testering.blorp(%{__struct__: Blah}) === "No-exception:  %{__struct__: Blah}"

My style here is of course a huge hack, it could be done properly in the compiler itself and more cleanly.

EDIT: Your box example (I think) could be done in my library as-is though (I’ve barely implemented it, just enough for the above examples to work, but this might work):

defmodule Box do
  import Defguard
  defguard is_filled(%Box{value: v}) when v != nil
end

...
  def foo(box) when is_filled(box) do
  end
2 Likes