Structs are implemented as maps.
However, throughout more recent Elixir versions, some sugar has been added
on top, which makes it easier to use a struct and more difficult to make
certain mistakes.
For instance:
- Specifying default field values as part of `defstruct`
- Compiler warnings when required struct fields are missing
- Compiler warnings when duplicate struct fields are used
- The possibility to override what exactly happens when someone writes
`%Struct{}` or `%Struct{a: 1, b: 2}`.
This last point makes it very easy to add extra checks (or other logic) to
the creation of a struct:
By overridding the generated `__struct__/1`-method, we have control over
how a struct is created, and can for instance provide more descriptive
errors when someone is breaking the invariants of our struct.
For who isn't aware of how this works:
- `%Struct{}` desugars to Struct.__struct__() (which internally, unless
itself overridden, calls `Struct.__struct__([])`)
- `%Struct{some: 1, field: 2}` likewise desugars to
`Struct.__struct__([some: 1, fields: 2])`.
However, there is one case which currently cannot be extended, because it
compiles down to a straight Erlang map update without using an intermediate
overridable Elixir method: The syntax `%Struct{my_struct | some: a}`.
Currently this directly is compiled to (the Erlang equivalent of):
```
case my_struct do
x = %{__struct__: Struct} ->
%{x | some: a}
other ->
raise BadStructError, struct: Struct, term: other
end
```
---
I propose to add a new function, for instance called
`__struct__(current_struct, changed_fields)`. Its implementation is exactly
the code Elixir currently already uses for the struct update syntax (e.g.
the one shown above).
Elixir could call this method during compilation just like what is already
done for __struct__/0 and __struct__/1 today. (or alternatively: just
adding `@compile inline: [__struct__: 2]` might accomplish the same without
having to evaluate it at compile-time?)
Thus, the normal effect will be exactly what happens today, without any
performance regressions or other problems.
However, we now have the possibility of adding extra checks which will be
executed whenever our struct is being updated.
---
Thank you for your consideration,
~Marten / Qqwy
--
You received this message because you are subscribed to the Google Groups
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/elixir-lang-core/3f2eb5f4-6f34-462d-8463-10fe2207524bn%40googlegroups.com.