Think about if it might at all be possible to support `@type t :: %__MODULE__{}` even above a `defstruct`
Qqwy opened this issue · comments
With the older checking implementation, this 'sort of' worked but silently did something not fully according to Elixir's typespec rules.
With the new checking implementation of the last minor revision, struct types were broken (c.f. #78 ).
The fix (#82) uncovered a related issue however: It is very common to write something like
defmodule User do
use TypeCheck
@type! t :: %__MODULE__{name: String.t(), age: integer()}
defstruct [:name, :age]
end
however this will currently fail with a compiler error.
What works, is:
defmodule User do
use TypeCheck
defstruct [:name, :age]
@type! t :: %__MODULE__{name: String.t(), age: integer()}
end
but I believe most style guides prefer the former, so a lot of code in the wild will use the former.
I'm not sure what, if at all, we can change to accommodate this, but it needs some thought.
I think this may be related to an issue I was running into with Ecto. Using Ecto's schema
macro automatically defines the struct, eg
schema "users" do
field :name, :string
end
means I automatically get %User{}
have the name field like: %User{name: nil}
in the struct.
However, if I define
@type! t :: %__MODULE__{}
schema "users" do
field :name, :string
end
I get an error telling me to move it below the defstruct. It works fine if I do
schema "users" do
field :name, :string
end
@type! t :: %__MODULE__{}
Yes, this is indeed exactly the same situation.
Thanks for mentioning, because hopefully it will help other people that might encounter this while using Ecto.
Are there any abilities to effectively move the position of the @type!
during compilation (e.g. blindly move to the end of the module)?
This requires the struct definition itself to be available at the time the datastructure containing the type-information is constructed.
Instead, it might be possible to introduce a new builtin type for structs, and defer the check to where the struct-type is used inside a type-check (that is, at compile-time in the implementation of TypeCheck.Protocols.ToCheck#to_check
).
Interesting. Do you mean similar to this sort of thing?... #21
I've come around to the idea of a shorthand for declaring typed structs so maybe this kills two birds with one stone.
For now, I think that having defstruct!
is probably enough.
A fix is definitely possible, but it will require quite a bit of work and I am not sure that it is worth the effort unless people are very frequently burnt/confused by this problem.
If it turns out to be a big problem in practice for people starting to use TypeCheck, then it is worth revisiting this issue.