Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Think about if it might at all be possible to support @type t :: %__MODULE__{} even above a defstruct #83

Closed
Qqwy opened this issue Nov 19, 2021 · 6 comments
Labels
help wanted Extra attention is needed

Comments

@Qqwy
Copy link
Owner

Qqwy commented Nov 19, 2021

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.

@Qqwy Qqwy added the help wanted Extra attention is needed label Nov 20, 2021
@rossvz
Copy link

rossvz commented Nov 30, 2021

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__{}

@Qqwy
Copy link
Owner Author

Qqwy commented Dec 1, 2021

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. 😃

@baldwindavid
Copy link
Contributor

Are there any abilities to effectively move the position of the @type! during compilation (e.g. blindly move to the end of the module)?

@Qqwy
Copy link
Owner Author

Qqwy commented Feb 21, 2022

🤔 I have a new idea to try out: Currently a struct is rewritten into a fixed_map-type exactly at the point where the type is constructed.

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).

@baldwindavid
Copy link
Contributor

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.

@Qqwy
Copy link
Owner Author

Qqwy commented Jun 7, 2022

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.

@Qqwy Qqwy closed this as completed Jun 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants