Closed metagn closed 6 years ago
I am not sure if this is about Language Design
. To me this looks like a bug or a regression, since code from the manual does not work as described anymore:
type
MyEnum {.pure.} = enum
valueA, valueB, valueC, valueD
echo valueA
The manual states that this code should give an error because of the pure
pragma, but it compiles and runs fine.
KR Axel
I agree this should be considered a bug, it defeats the whole purpose of using pure
on an enum
.
There was a discussion not so long ago where @Araq argued that there is no issue in allowing non-qualified access to pure enums, as long as no ambiguity arises.
Hence the condition on pure enums was relaxed a bit. The problem here is that there is an ambiguity.
In my opinion, allowing only qualified access to pure enums is a simple and clear rule to explain and to follow, and I do not see much value in allowing non qualified access.
Yes, you don't see much value. I've actually tried to use the old pure
enums though and they are terrible. {Foo.valA, Foo.valB}
violates DRY and so you need even more complex rules like "In a set construction, the prefix can be avoided. Oh and in case statements too. Oh and in array constructions..."
And then these rules fail to be applied in DSLs...
@Araq I actually don't have any problems in relaxing the conditions for pure enums, the current issue is just a bug that needs to be ironed out. I was just trying to reconstruct why things changed.
Even if I don't see much value in this particular circumstance, I am mostly agnostic about whatver choice gest implemented for pure enums
I'd also be alright with it after hearing the rationale, provided this bug gets fixed and the compiler gives useful error messages similar to other ambiguities.
Relevant discussion in 2017 from @dom96, @PMunch, @Araq and me https://irclogs.nim-lang.org/22-10-2017.html#13:54:23
Time Person Text 13:54:23 dom96 I don't get it. You don't have to prefix enum names even when {.pure.} is specified? 14:03:38 Araq dom96, pure enum field names get their own scope that is queried if the name was not found in any other scope 14:04:09 Araq so as long as nothing else clashes with it you can use these names without the Enum. prefix 14:04:35 dom96 So now the only difference is that I cannot use a prefix for non-pure enums 14:04:56 Araq er, sure you can 14:04:56 dom96 This behaviour should be implemented for non-pure enums and pure enums should have been left alone 14:05:19 dom96 so what's the difference between pure/non-pure enums now? 14:05:21 Araq well the point is to remove the whole distinction between the two enum types 14:05:57 dom96 er, so you've basically removed {.pure.}? 14:07:09 FromGitter \<mratsim> So this should be updated: https://nim-by-example.github.io/types/enums/ 14:07:27 PMunch Pure was nice though.. 14:07:44 dom96 It is nice. 14:07:48 Araq I unified the two concepts, not sure why you don't understand it 14:07:57 dom96 Which is why I'm trying to understand what the purpose of Araq's changes is 14:08:09 FromGitter \<mratsim> It should be named "qualified" instead of pure though. 14:08:09 Araq "pure was nice though", omg you can still prefix them all you want 14:08:23 PMunch But you can't force people to.. 14:08:27 dom96 indeed 14:08:32 PMunch I thought that was the entire point of pure 14:08:39 dom96 precisely 14:08:43 Araq the point was to prevent clashes 14:08:50 PMunch To say: this symbol doesn't make any sense without the enum name 14:09:10 dom96 But you've just said that you can prefix non-pure enums too 14:09:21 dom96 so if there are clashes you can prevent them 14:09:31 PMunch And what happens if you have "OneEnum.test" and "AnotherEnum.test", both marked as pure. What will test refer to? 14:09:38 FromGitter \<mratsim> you will still get "ambiguous call" though? I guess itÔøΩs the same discussion as {.this:this.} pragma 14:09:56 Araq it never was about enforcing rules, it was about preventing clashes 14:10:14 Araq nobody wants these rules anyway: 14:10:17 Araq case e 14:10:24 Araq of SomeEnum.valueA: 14:10:28 Araq of SomeEnum.valueB: 14:10:38 dom96 I do 14:10:44 Araq of SomeEnum.valueC: echo "just kill me already" 14:10:57 dom96 Sometimes it makes sense to have a short enum value name 14:11:04 dom96 and then a qualifying prefix that is long 14:11:19 dom96 In that case I want to force the user of my library to prefix the enum 14:11:46 Araq yeah, that is exactly what Nim is NOT about 14:11:55 Araq your users are adults. 14:13:22 Araq if foo in {SomeEnum.short, shortToo, shorter} 14:13:38 Araq # ^ context is everything 14:16:27 PMunch Hmm, I still feel this should be handled somehow else.. 14:16:51 dom96 okay, then we should get the ability to enforce this when importing enums 14:17:36 dom96 btw my book mentions the pure pragma 14:18:19 PMunch TBH, that shouldn't be a factor in the language design 14:18:30 PMunch Of course it's not good, but such is life.. 14:19:22 dom96 True. 14:20:01 Araq people argued that every enum should be pure and then we should have special rules in 'case' and set literals to be able to avoid the prefix 14:21:06 PMunch That makes more sense.. 14:21:13 Araq but this doesn't work well, what about [value: "a", valueB: "b"] array constructions 14:22:51 PMunch "SomeEnum.[value: val1, valueB: val2]" for "type SomeEnum = enum val1, val2" 14:23:05 PMunch Same for set 14:23:49 PMunch Case is the only special thing 14:24:37 Araq that's not true at all 14:25:41 Araq in Karax for example the problem comes up all the time too, we want a CSS "enum" without the prefixes that yet doesn't clash 14:26:11 Araq registerEvent(onclick, proc ...) 14:26:28 Araq # ok, onclick is nothing unexpected here 14:26:55 Araq registerEvent(Event.onclick, proc ...) # some other onclick clashed so I need to write it out 14:27:23 dom96 It's hard to tell that onclick
is an enum type14:27:33 dom96 it could be a procedure 14:27:41 Araq it's superior to your "I want to enforce it everywhere until I figured out that's a horrible idea" 14:27:43 dom96 forcing the prefix makes it clearer 14:27:49 dom96 It makes the code far more readable 14:27:54 PMunch Agreed 14:28:03 Araq no, I disagree and Nim doesn't work this way 14:28:20 miran prefix sometimes makes things clearer 14:28:33 Araq everything else in the language doesn't work this way either anyway 14:28:41 dom96 But sadly this indeed isn't how Nim was designed 14:29:37 Araq Event.onclick # you don't know anything about enums here, could also be ModuleName.onclick 14:29:38 PMunch Fair enough
I still think if the pragma is here to stay, {.pure.}
should be renamed {.qualified.}
, and {.qualified.}
should always require the enum prefix. {.pure.}
is not really descriptive of what the pragma does. (And maybe we should have import qualified Foo
instead of from Foo import nil
)
But, I think this is unnecessary policing by the compiler, assuming this is an internal enum, you're free to use your preferred style (always qualifying, or qualifying when necessary), if it's a public module, don't force your style on other projects.
All in all I think this should be handled in a Nim linter, with options chosen by the library authors, not in the compiler.
Just an opinion,
I like that you don't to prefix everything with MyEnum.
it saves a lot of strokes. I think just error message needs to be improved for example above. Nim should say that red
is ambiguous.
I think the focus was mishandled in this issue, it's also a matter of not having to deal with hungarian notation or the full name of the enum in the enum member like SDL_SCANCODE_UNKNOWN
instead of Scancode.Unknown
. To better express my point:
type StreetLight {.pure.} = enum
red, yellow, green
let foo = StreetLight.red
instead of
type StreetLight = enum
stlRed, stlYellow, stlGreen
let foo = stlRed