Hello everyone,
I am just beginning to learn nim, a great language btw! I have a question regarding the "redefinition" error that I get:
I have declared the enum type like so:
type
SomeEnum* = enum
nice
# And then I declare a proc like so:
proc nice (str: string) : string =
return str & " something here"
This leads to an Error - redefinition of 'nice' What can I do to fix it / avoid it?
Thank you very much for your time!
P.S.
Enum manual: "Each symbol is mapped to an integer value internally"
It was not obvious that enum's symbols would be mapped in the same block of code.
Enum manual: "An enumeration's symbol can be qualified to avoid ambiguities: Direction.south"
My first thought was to try to look up in pragmas section for something that might force to remove such ambiguity in the first place. I mean something like {.unambiguous.}, so that compiler might force the use of SomeEnum.nice so that redefinition would not occur.
P.P.S. As suggested, {.pure} pragma is what I was looking for! Cheers!
pure pragma helps: http://nim-lang.org/docs/manual.html#pragmas-pure-pragma
type
SomeEnum* {.pure.} = enum
nice
# And then I declare a proc like so:
proc nice (str: string) : string =
return str & " something here"
O great, now I see it:
Pragmas manual: "An enum type can be marked as pure. Then access of its fields always requires full qualification."
Would be great to see an example there.
Thank you very much for the help!
gogromat: It was not obvious that enum's symbols would be mapped in the same block of code.
Er, where else? The whole point of defining your enum type is to make it and its values visible within its lexical scope, isn't it?
gogromat: Would be great to see an example there.
A description and example of {.pure.} is given in http://nim-lang.org/docs/manual.html#types-enumeration-types
@jibal Yes, absolutely. What I meant it was not obvious that the enum's symbols will be mapped as integers and I would not be able to reuse the values in the same block of code (here {.pure} helps). Also sounds wrong...Ok, I completely overlooked that line about integer mapping and did not know how to make a proc with same name.
@jibal Nice! I remember I saw a description somewhere, but could not find it the second time around, thanks for the link!
" What I meant it was not obvious that the enum's symbols will be mapped as integers"
Well, that's what the documentation says, and it's hard to imagine what else they would be mapped to, so it seems obvious to me.
"and I would not be able to reuse the values in the same block of code"
You aren't trying to reuse "values", you're trying to redefine a name (nice) in the same scope, which is verboten in every language I can think of, so again that seems obvious to me. The solution to this in Nim is to either use {.pure.} or to follow the practice of adding a prefix to the enum symbols, as discussed in https://github.com/nim-lang/Nim/wiki/Style-Guide-for-Nim-Code
Unless marked with the {.pure.} pragma, members of enums should have an identifying prefix, such as an abbreviation of the enum's name. Since non-pure enum members can be referenced without full qualification [an example is given]
This harks back to the convention for C struct members back before each struct had its own namespace (that was before UNIX Version 7), and is familiar to C programmers who use OS-defined structs such as struct stat and struct tm, which date back to that time. At least Nim offers a choice as to whether enum symbols have their own namespace, but I would favor making it easy to use {.pure.} enums by allowing omission of the enum type when it can be inferred, as Swift does.
@jibal Very interesting, thanks for writing it! I actually haven't used enums before, the languages I worked before with (PHP/Javascript/Go) don't have them (as far as I know). I just assumed that you always need full qualification when working with enums, again my fault :]
Regarding the Swift, from reading the enum manual it says that the enum's type is inferred after you initialize it to a variable? So as I understand you can't directly reference enum without full qualification. And you still need to reference the value using dot notation (if you are not using full qualification): .North
So again I was puzzled at how flexible the nim compiler is, it will check for redefinition of a variable, even when used in proc, even without the dot notation (as in Swift?).
So my initial thought was that the compiler will know that nice("proc call") is different from var a = nice, but I see it's difficulty - it's hard to tell whether var a = nice is a reference to enum's value (zero) or a proc (like using a callback in some context). I guess that's why in Swift it has a dot notation in front? So compiler will know that you are trying to reference a certain type. Again that's just my thoughts :]
(PHP/Javascript/Go) don't have them (as far as I know)
Go is a backwards language that just uses const together with iota ... abandoning both qualification and type safety, a la C. Many languages do have them; see https://en.wikipedia.org/wiki/Enumerated_type
I just assumed that you always need full qualification when working with enums
In some languages you do and in some you don't ... the former tend to be a pain because of the verbosity. AFAIK Nim is the only language that provides a choice, but I think Swift's design that takes advantage of type inference is better and Nim would do well to follow the same approach.
Regarding the Swift, from reading the enum manual it says that the enum's type is inferred after you initialize it to a variable?
It's simply a matter of having a type to infer ... assigning an enum value to a variable with a known type tells you that the type of the enum is the type of the variable, so full qualification isn't necessary. It also isn't necessary in other contexts where the type can be inferred, such as a function argument or a case statement.
And you still need to reference the value using dot notation (if you are not using full qualification): .North
Yes, although they didn't strictly have to require it; see below.
So my initial thought was that the compiler will know that nice("proc call") is different from var a = nice, but I see it's difficulty
Consider a worse case:
type SomeEnum = enum nice
var nice = 42
var what = nice
What's the poor compiler supposed to make of that? Nim's procs names, vars, types, and enum values (unless {.pure.}) are all in the same namespace, which makes things consistent and easy to understand and allows context-free parsing (and syntax coloring).
I guess that's why in Swift it has a dot notation in front? So compiler will know that you are trying to reference a certain type.
As I noted above, the dot shouldn't strictly be necessary because the dotted enum names can only be used where the type can be inferred, so there's no ambiguity:
var foo = .nice // not allowed; must be SomeEnum.nice
var foo: SomeEnum = .nice // ok, and the compiler would know what nice is even without the dot
I'm not sure why they decided to require the dot, but it does make the code clearer I suppose.
I would love to see Nim allow omission of the type (and possibly the dot) for {.pure.} enum values when it can infer them ... and then make {.pure.} the default.