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 <bamo...@gmail.com> 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 <lo...@lpil.uk> 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, <bamo...@gmail.com> 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 elixir-lang-co...@googlegroups.com.
>>>> 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 
>>> elixir-lang-co...@googlegroups.com.
>>> 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 elixir-lang-co...@googlegroups.com.
>>
> 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 elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/4f7a133f-3394-4376-bf6c-e87bf0f8a1a7n%40googlegroups.com.

Reply via email to