smolcatgirl
Allow specifying the type when defining structs
Hi,
I think it would be cool to be able to require a certain type for my fields when I create structs. Like specifying one field should be a integer and another a list. So I am not talking about Ecto schemas but regular structs with type checking. What do you think?
Thanks for reading!
Most Liked
tme_317
I use https://github.com/ejpcmac/typed_struct for all of my structs. The built-in dialyzer integration provided by the Elixir LS editor plugin does the checking.
al2o3cr
What specific operations would this provide? “Type checking” can mean a lot of things in Elixir:
-
compile-time success-type checking, as provided by Dialyzer
-
runtime pattern matching and guards, like:
def some_function_that_wants_a_list(x) when is_list(x) do
- field enforcement on structs; a mostly compile-time guarantee that specified keys will be in a map tagged with the
__struct__key. For instance, this will fail if the target struct doesn’t have afookey already:%{target | foo: "bar"}
typed_struct (recommended in this thread) is ultimately just a shorthand for writing a Dialyzer typespec and defstruct; the compiler ultimately sees the same code.
To return to my original question, what kind of “type checking” behavior are you looking for? For concreteness, let’s imagine we have a “typed struct” called Blog that expects its tags field to be an array of strings. What should the following do:
%User{tags: 1234}- wrong type%User{tags: ["a", 1234])- mixed types in a field%{some_user | tags: 1234}- update with wrong type%{some_user | tags: ["a", 1234]}- update with mixed types%{some_user | tags: value_that_might_be_a_list_at_runtime}- compiler has no informationMap.put(some_user, :tags, 1234)- structs are maps too
Dialyzer will catch some of these, when it has enough information to prove things are the wrong types - but it’s going to struggle with things like the value_that_might_be_a_list_at_runtime case and give up ENTIRELY on the Map.put one.
Communicating typing failures out of these constructs is going to be difficult - they don’t normally “fail”, so the only available option is to crash the process.
Also note that all of these constructs are used extensively in Elixir’s implementation - so any overhead added will be significantly amplified. That’s one reason to prefer an opt-in library like Ecto.Schema, which layers the additional functionality onto bare structs instead of adding more complexity directly to them.
mat-hek
What are you worried about? A several dozen of kilobytes extra on your drive?
Maybe about
- the need for keeping track of updates of that dependency
- potential conflicts delaying updates of other dependencies
- introducing potential vulnerabilities
- extended compilation time
- waking up when a dozen kilobytes turns into hundreds of megabytes, as in case of NPM and node_modules
So definitely having as little unused stuff in your deps as possible is a good approach ![]()







