Hello world. Here is my code:
type
INT16TO64 = int | int16 | int32 | int64 | uint | uint16 | uint32 | uint64
proc echoI(i: int8 | uint8) = echo "i8: ", i #Prints 8-bits ints
proc echoI(i: INT16TO64) = echo "i: ", i # Prints all other ints
echoI 56
This code returns an "ambiguous call" error. When I type echo 56 is int8 | uint8, Nim prints "false". When I type echo 56 is INT16TO64, Nim prints "true". Then why don't it just call the INT16TO64 version of the proc?
@PMunch
Sorry, I really don't like your reply -- maybe I am too stupid to understand it.
echo(typeof(56)) will display int
var i = 56 # will give i the int type
Citing the manual: "Literals without a type suffix are of an integer type unless the literal contains a dot or E|e in which case it is of type float."
So for me it is just an interesting compiler behaviour.
@archnim
Have you started reading? You have not replied to my github issue in your Ina package some weeks ago?
This is due to how Nim handles literals. The followimg exhibits the same behaviour.
proc doThing(i: float) = discard
proc doThing(i: float32) = discard
doThing 10
Yes typeof(10) is int but not all int literals are int, context changes their type. Consider var a: byte = 255 or var a: float = 3 the compiler implicitly converts to the type. In the case of an overloaded call like this it does not know to convert to the generic 8bit ints or the generic remainder. To a point if we do echoI int(56) it calls the expected procedure and runs.proc doThing(i: float) = echo typeof(i)
doThing 10 # float
If I add doThing(i: int) proc, doThing 10 calls it:
proc doThing(i: int) = echo typeof(i)
proc doThing(i: float) = echo typeof(i)
doThing 10 # int
Just adding a proc can change which proc existing call statement calls. Doesn't this cause a hard to debug problem in a large code? Just adding an import statement to a code can change behavior. Can you easily find procedures that caused it in large code?
Well, that's the nature of function overloading. It's not normally an issue because the problem only applies to procedures with the exact same name that relies on int literals not having a concrete type. It's a very small scenario, and personally I don't think I've ever come across loading a library changing the behavior like that.
And @Stefan_Salewski, not quite sure what you don't like about it. ElegantBeef explained this in a bit more detail. Essentially it goes something like this:
5 # This is an undetermined int literal
var x: float = 5 # Now the int literal is required to be turned into a float, which is fine, because it's an undetermined int literal
var y = 5 # Now the undetermined int literal needs to take on a concrete type and chooses the default one, an int, since no type is required.
echo typeof(5) # Typeof can't return "I don't know" so the undetermined int literal once again have to choose a type, and goes with the default.
var f = [1.0, 4.2, 5] # The undetermined int literal again turns into a float, because it is requested to be one
The reason for this tiny pseudo-type is simply to allow us to type less, and it rarely creates bugs. The above could certainly have been avoided by choosing the default type in an ambiguous situation (same as it does in var y = 5) so I guess this could be considered one such bug.And @Stefan_Salewski, not quite sure what you don't like about it.
Because you did not really explained it. You started the paragraph with "Because 56 is an undetermined int literal," which is already a questionable statement. At least I have seen better explanations of you in the past. :-) With the additions of Mr. Beef its got a bit more clear.
The problem is really interesting, this works fine:
proc p(i: int) =
echo "p1: ", i * i
proc p(i: int8) =
echo "p2: ", i * i
p(1)
p1: 1
But this does not compile:
proc p(i: uint8) =
echo "p1: ", i * i
proc p(i: int8) =
echo "p2: ", i * i
p(1)
/tmp/hhh/t.nim(7, 2) Error: ambiguous call; both t.p(i: uint8) [proc declared in /tmp/hhh/t.nim(1, 6)] and t.p(i: int8) [proc declared in /tmp/hhh/t.nim(4, 6)] match for: (int literal(1))