I think parameterized types might help a little in this case:
@type t() :: t(integer() | nil)
@type t(a) :: %__MODULE__{
a: a,
b: integer() | nil,
c: integer() | nil
}
@type my_struct_with_a() :: t(integer)
On Saturday, February 6, 2021 at 7:50:41 AM UTC+1 José Valim wrote:
> I completely agree with the needs for this feature but unfortunately it
> must be implemented upstream on Erlang first.
>
> The reason why is because if we were to expand the initial map within
> Elixir, it will both be expensive (we may need to augment a remote type,
> which would require loading and traversing beam files) and add a compile
> time dependency.
>
> If this is part of Erlang, none of those are required.
>
> On Sat, Feb 6, 2021 at 01:54 Bernardo Amorim <[email protected]> wrote:
>
>> I was expecting that to be a compile time transformation that would
>> generate the exact same compiled erlang as
>> ```
>> @type my_struct_with_a() :: %MyStruct{
>> a: integer(),
>> b: integer() | nil,
>> c: integer() | nil
>> }
>> ```
>>
>> But that would require `@type` to be able to get the AST for
>> `MyStuct.t()` during compile time.
>>
>> On Fri, Feb 5, 2021 at 8:21 PM Louis Pilfold <[email protected]> wrote:
>>
>>> Hello!
>>>
>>> Correct me if I'm wrong but I believe this isn't something that Erlang
>>> typespecs support, or at least there is no syntax for it.
>>>
>>> What do you see this compiling to? Elixir has to work with the
>>> capability of Erlang here.
>>>
>>> Cheers,
>>> Louis
>>>
>>> On Fri, 5 Feb 2021, 22:39 Bernardo Amorim, <[email protected]> wrote:
>>>
>>>> Hi folks, I'm not even sure if this is possible nor if it was raised
>>>> before nor if there is already another way of doing something similar. But
>>>> this is something that I've been thinking a lot recently and I'd like to
>>>> know if it is possible and desirable. If it is, I can help with a PR later
>>>> on.
>>>>
>>>> The "problem":
>>>>
>>>> It is usual to when we have a Struct (specially Ecto.Schemas) to define
>>>> a `@type t()` with the fields. Let's say we have a Struct with a few
>>>> fields
>>>> like this:
>>>>
>>>> ```
>>>> defmodule MyStruct do
>>>> defstruct [:a, :b, :c]
>>>> @type t() :: %__MODULE__{
>>>> a: integer() | nil,
>>>> b: integer() | nil,
>>>> c: integer() | nil
>>>> }
>>>> ```
>>>>
>>>> Now imagine I want to define a function that receives a struct but
>>>> requires one of these fields to be non null. What we have to do right now
>>>> is to:
>>>>
>>>> ```
>>>> @type my_struct_with_a() :: %MyStruct{
>>>> a: integer(),
>>>> b: integer() | nil,
>>>> c: integer() | nil
>>>> }
>>>> ```
>>>>
>>>> (Ok, maybe in some cases we do not need to redefine all the other
>>>> fields since they might be irrelevant, but let's assume we actually want
>>>> to
>>>> type everything)
>>>>
>>>> The proposal:
>>>>
>>>> For map values when we just want to change one field we can do
>>>> something like: ```%MyStruct{my_struct | a: 1}```, but for types this is
>>>> not possible.
>>>>
>>>> My proposal would be to have something like this:
>>>>
>>>> ```
>>>> @type my_struct_with_a() :: %MyStruct{MyStruct.t() | a: integer()}
>>>> ```
>>>>
>>>> That would generate a type with all fields copied from `MyStruct.t()`
>>>> but with `:a` changed to `integer()` instead of `integer() | nil`.
>>>>
>>>> The caveats I see is what to do when the type is not just a map type
>>>> (maybe it is a sum type, maybe it is not even a map, etc).
>>>>
>>>> What do you folks think about this?
>>>>
>>>> Thanks,
>>>> Bernardo Amorim
>>>>
>>>> --
>>>> 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 [email protected].
>>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/elixir-lang-core/b152b04f-3c6b-4052-92aa-d23724ed0f92n%40googlegroups.com
>>>>
>>>> <https://groups.google.com/d/msgid/elixir-lang-core/b152b04f-3c6b-4052-92aa-d23724ed0f92n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>> --
>>>
>> You received this message because you are subscribed to a topic in the
>>> Google Groups "elixir-lang-core" group.
>>> To unsubscribe from this topic, visit
>>> https://groups.google.com/d/topic/elixir-lang-core/gvLUM0asfmI/unsubscribe
>>> .
>>> To unsubscribe from this group and all its topics, send an email to
>>> [email protected].
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/elixir-lang-core/CABu8xFCeqgNAOp1o%3D0JJ%2B9JYwF20H9-%2BnD2DLoY%3DuSisyGB8NA%40mail.gmail.com
>>>
>>> <https://groups.google.com/d/msgid/elixir-lang-core/CABu8xFCeqgNAOp1o%3D0JJ%2B9JYwF20H9-%2BnD2DLoY%3DuSisyGB8NA%40mail.gmail.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 [email protected].
>>
> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/elixir-lang-core/CAJVmgvBectadT%3DYaT7tFtyG03APUcsyJWQU8922Y_9zuYb7jxA%40mail.gmail.com
>>
>> <https://groups.google.com/d/msgid/elixir-lang-core/CAJVmgvBectadT%3DYaT7tFtyG03APUcsyJWQU8922Y_9zuYb7jxA%40mail.gmail.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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/elixir-lang-core/4f7a133f-3394-4376-bf6c-e87bf0f8a1a7n%40googlegroups.com.