I think this could be pretty cool.

I'm curious though, are there checks that Elixir performs, that
implementing your own version of these would violate?
For example, the map update syntax will only allow existing keys, but I
could presumably accept keys that aren't present and do some transformation
on them before updating the struct. If I wrote __struct__ to support keys
that aren't present in the struct, will I get some warning from Elixir
about it?

There's also this syntax for updating a struct.
defmodule Pair do
  defstruct x: 1, y: 2
end
%Pair{%Pair{} | y: 3}

I don't recall if this is different then the map update syntax, but I feel
like it was last time I checked. How does that fit into your proposal?

Allen Madsen
http://www.allenmadsen.com


On Mon, Apr 25, 2022 at 10:31 AM w...@resilia.nl <w...@resilia.nl> wrote:

> 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
> <https://groups.google.com/d/msgid/elixir-lang-core/3f2eb5f4-6f34-462d-8463-10fe2207524bn%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
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/CAK-y3CuGGv7VUt%2BzOp4K_z931JYK_TGDje-9eQLQ4ryDRS70EQ%40mail.gmail.com.

Reply via email to