Hello!
I’m finally digging into Elixir again after a few years, and I started toying around with protocols and derivations and such. I generally understand it, but the seemingly canonical example of Poison.Encoder
is evading me a bit. For reference: https://github.com/devinus/poison/blob/master/lib/poison/encoder.ex#L372-L412
Specifically, I’m confused about how the deriving
function works, given that the struct
parameter is unused, but is also later referenced in the quote
block:
defimpl Poison.Encoder, for: Any do
alias Poison.{Encoder, EncodeError}
defmacro __deriving__(module, struct, options) do
deriving(module, struct, options)
end
def deriving(module, _struct, options) do
only = options[:only]
except = options[:except]
extractor =
cond do
only ->
quote(do: Map.take(struct, unquote(only)))
except ->
except = [:__struct__ | except]
quote(do: Map.drop(struct, unquote(except)))
true ->
quote(do: :maps.remove(:__struct__, struct))
end
quote do
defimpl Encoder, for: unquote(module) do
def encode(struct, options) do
Encoder.Map.encode(unquote(extractor), options)
end
end
end
end
def encode(%{__struct__: _} = struct, options) do
Encoder.Map.encode(Map.from_struct(struct), options)
end
def encode(value, _options) do
raise EncodeError, value: value
end
end
I understand that, within the quote
block, the reference to struct
is not actually a “reference” per se, and rather it just yields the AST for a variable of name struct
. That’s fine… but I’m confused as to how it ends up being useful when the __deriving__
macro is called? We pass the struct
along to the deriving
function clearly, but it’s then unused… so what happens?
I think I might almost get it, in that my mind leans toward some fuzzy notion of “well yea, but it gets returned to… something… as the proper AST that will be evaluated as needed”… but that still feels vague and not really something I understand, assuming it’s not totally wrong.
Thanks!