-
Notifications
You must be signed in to change notification settings - Fork 36
Add parameters option #28
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
Conversation
Allows to add paramameters to the generated struct type.
For example:
typedstruct parameters: [a, b] do
field :a, a
field :b, b | nil
field :c, integer()
end
Generates the type:
@type t(a, b) :: %__MODULE__{
a: a,
b: b | nil,
c: integer()
}
70c3300 to
3399d7b
Compare
Change examples because put_in() is not properly analyzed by dialyzer.
|
Hello @flupke, Indeed, this is a good idea! I’m myself using the typestate pattern in Rust, but have never used it in Elixir. I’ll try to find some time to look into your PR and debug it in the days to come, and let you know. The compiler is currently complaining that what you are passing to the |
|
I tried with In this SO answer they seem to declare arguments names as-is. They also do the same in Ecto bindings: I say the error seems to come from # This
quote bind_quoted: [types: types, type_parameters: type_parameters] do
@type t(unquote_splicing(type_parameters)) :: %__MODULE__{
unquote_splicing(types)
}
end
|> Macro.expand(__ENV__)
|> Macro.to_string()
|> IO.puts()
# Expands into this
types = @ts_types
type_parameters = [a, b]
@type t(unquote_splicing(type_parameters)) :: %__MODULE__{unquote_splicing(types)}And if I remove the content of the type_parameters = [a, b]I tried to remove I can get the test to compile with this: # This code
defmacro __type__(types, opts) do
type_parameters = Keyword.get(opts, :parameters, [])
quote do
@type t(unquote_splicing(type_parameters)) :: {a, b}
end
end
# Expands to
@type t(a, b) :: {a, b}So it seems I'm going in the right direction, but I can't figure out how to get both So that's why I'm stuck, and since I have no idea what I'm doing I decided to stop trial and error and to ask for help :) I have a basic understanding of how macros work, but How did you learn all this? :) |
|
Hello, unfortunately I just learned dialyzer doesn't check type parameters and treats them as See the discussion on slack: https://elixir-lang.slack.com/archives/C03EPRA3B/p1663778934745189 More specifically: https://elixir-lang.slack.com/archives/C03EPRA3B/p1663780274897679 And my proposed workaround: write a macro parameterized_union do
type a, b() | c()
type b, e() | f(), private: true
union generic(x, a, b), {t(), x}
endthat expands to @type a :: b() | c()
# b is not in the output but is used in the union
@type generic_a :: {t(), b()} | {t(), c()}
@type generic_b :: {t(), e()} | {t(), f()}I don't think this fits in typed_struct scope though... |
|
Humm nevermind the person who told me that was wrong, parameterized types are checked just fine. My macro is completely useless and doesn't help at all, the rule just seems to be dialyzer gives up in complex situations, whatever that means. For example these specs are checked just fine: @type foo :: 1 | %{a: 1}
@type generic(x) :: {:ok, x} | {:error, x}
@spec bar() :: generic(foo)
def bar do
if div(System.time_offset(), 2) == 0 do
if div(System.time_offset(), 2) == 0 do
{:ok, 1}
else
{:ok, %{a: 1}}
end
else
if div(System.time_offset(), 2) == 0 do
{:error, 1}
else
{:error, %{a: 1}}
end
end
end |
|
Closing in favor of #34 |
Hello,
First of all thank you very much for your library, it's great!
I stumbled upon this blog post explaining the Typestate pattern, and thought it was great too. Unfortunately I don't think it's possible to implement this with
typed_structbecause the generatedt()can't have parameters.So I tried to add a
parametersoption totypedstruct, but couldn't get it to work:If you think this would be a good addition to your library, could you please have a look and nudge me in the good direction?
I feel I'm close to success but it's my first time fiddling with Elixir macros and honestly I'm lost. It looks like the problem comes from the
bind_quoted:stuff in__type__()but I don't really understand what it does and couldn't find information about it, nor understand why you're using it.Thanks,
Luper