-
Notifications
You must be signed in to change notification settings - Fork 10
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
Allow explicit enum values #114
base: master
Are you sure you want to change the base?
Conversation
👋 thanks for the PR 😉 Personally I find quite unobvious that the alternative of tuples maps to an enum 🤔 What about @type foo :: enum(a: 1, b: 2)
@type foo :: enum({:a, 1} | {:b, 2})
@type foo :: enum_value(:a, 1) | enum_value(:b, 2) I like the last one the most, except that |
I agree it's not the best syntax, so I'm happy to see more suggestions. Something all three of your suggestions highlight is the use of the word "enum". I think it would be helpful to change the spec dsl to use |
@type foo :: enum_value(:a, 1) | enum_value(:b, 2) I think this option is the best of the three you mentioned. @harrisi even if we would introduce The general disadvantage of using names with WDYT about something like @type my_type :: (:a :: 1) | :b | (:c :: 100) |
I hadn't thought about this, but good point. Having two ways of defining enums (with The main issue I have with using something like
The precedence makes it so that parsing this is either very strange, or the parentheses are mandatory, which seems weird. Without parentheses: {:@, [context: Elixir, imports: [{1, Kernel}]],
[
{:type, [context: Elixir],
[
{:"::", [],
[
{:my_type, [], Elixir},
{:"::", [],
[:a, {:"::", [], [{:|, [], [1, {:|, [], [:b, :c]}]}, 100]}]}
]}
]}
]} with parentheses: {:@, [context: Elixir, imports: [{1, Kernel}]],
[
{:type, [context: Elixir],
[
{:"::", [],
[
{:my_type, [], Elixir},
{:|, [],
[{:"::", [], [:a, 1]}, {:|, [], [:b, {:"::", [], [:c, 100]}]}]}
]}
]}
]} |
Right, another idea: @typemap a: 1, c: 100
@type my_type :: :a | :b | :c |
Having the definitions be separate seems weird, since there's a whole new type of errors to handle. What if the typemap includes extra keys? Should the order matter? Etc. I'm not sure how y'all feel about it, but I'm kind of coming back around to the |
Yeah, unfortunately, all the approaches are a bit weird, because we're trying to connect two totally different worlds :P I'd lean towards the typemap thing, as it's not using syntax that has very different semantics in regular Elixir/specs, cc @FelonEkonom
I think it's ok to raise an error
The order would be as in the |
Yeah, I was more just bringing up that there exists a new class of error with a separate "
What I mean is type foo :: :a | :b | :c
typemap foo :: [a: 1, c: 4]
# later on: "huh, you know, I think `b` should be defined after `c`, actually.."
type foo :: :a | :c | :b
# uh oh, the enum changed from `1, 2, or 4` to `1, 4, or 5`. Obviously changing the order of enums requires care anyway, but having the definition be separated in two calls isn't something that's familiar in C, so it seems easier to miss and have weird things happen. The fix for this would be to enforce I'm not too concerned about the syntax, so I'll just say my preference is either |
@harrisi good point about paying attention to the order of fields in enum 👍 |
@harrisi after internal discussion we decided that we like the option with Thanks 👍 |
How would y'all feel about using a keyword list? Either instead of a 2-arity "function", or in addition to? So, type foo :: enum_value(a: 1) | :b | enum_value(:c, 4) would be valid if both are allowed? I don't love having two ways to define it, but the single element keyword list kind of feels better to me. It doesn't really make parsing meaningfully more complex to allow both. |
IMO it seems weird to make Personally I would stay with |
Sounds good! Let me know if there's anything else to add. |
@harrisi I don't see a need for anything else right now. Is this PR ready to review? |
Should be! :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Fix failing tests, probably you will have to update fixture files.
- Fix credo, try
mix deps.update credo
and see if it helps.
Merged the credo update from #115, fixed a few errors, updated test fixtures. Sorry, I thought I did those things already. Forgot where things were at in the few weeks break there! Hopefully that resolves everything. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beyond one comment to the docs everything looks fine
Enum constants can be given an explicit value with `enum_value` | ||
|
||
type my_explicit_enum :: enum_value(:option_one, 1) | :option_two | :option_three | ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please mention, that second argument passed to enum_value/2
can be used only in the code in C/C++ while Elixir API still supports only atoms
This PR adds the ability to set values for enums, so this type of C code can be generated:
The syntax I went with is the following:
The only real alternative I could think of would be something like this:
I don't like this, since it's nonsensical in normal Elixir.
I originally thought a list would be okay, something like this:
But this doesn't allow for partially explicit definitions, unless all the explicit definitions are at the end (to make it a valid keyword list), so the above definition isn't possible:
I think the desugared pseudo-keyword list is a decent option. It seems less weird than writing
:a = 1
to me, anyway. It could also be defined as a list (e.g.,[:a, 1] | :b
), but that seems confusing since[type]
is meaningful elsewhere.