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 elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/3f2eb5f4-6f34-462d-8463-10fe2207524bn%40googlegroups.com.

Reply via email to