write requires conversion to string
type
Kind = enum INT, STR, ELT
Tree = ref object
case k: Kind
of INT: i: int
of STR: s: string
of ELT:
e: string
a: seq[(string, string)]
b: seq[Tree]
proc tree(x: int): Tree = Tree(k: INT, i: x)
proc tree(x: string): Tree = Tree(k: STR, s: x)
proc write(f: File, x: Tree) =
case x.k
of INT: f.write x.i
of STR: f.write x.s
of ELT:
f.write '('
f.write x.e
f.write ' '
for (k, v) in x.a:
f.write k
f.write '='
f.write v
f.write ' '
for i in x.b:
f.write i
f.write ')'
stdout.write tree 42
rec.nim(29, 15) Error: type mismatch: got <Tree>
but expected one of:
proc `$`(x: bool): string
proc `$`(x: int64): string
proc `$`(w: WideCString; estimate: int; replacement: int = 0x0000FFFD): string
proc `$`(x: char): string
proc `$`(x: float): string
proc `$`(x: cstring): string
proc `$`[T](x: openArray[T]): string
proc `$`[T, IDX](x: array[IDX, T]): string
proc `$`(s: WideCString): string
proc `$`(x: string): string
proc `$`[T: tuple |
object](x: T): string
proc `$`[Enum: enum](x: Enum): string
proc `$`(x: uint64): string
proc `$`(t: typedesc): string
proc `$`[T](x: set[T]): string
proc `$`[T](x: seq[T]): string
proc `$`(x: int): string
proc `$`[T, U](x: HSlice[T, U]): string
s/write/mywrite fixes the example
but i would expect that my write method would be used
$ nim -v
Nim Compiler Version 0.20.2 [Linux: amd64]
Compiled at 2019-07-17
Copyright (c) 2006-2019 by Andreas Rumpf
active boot switches: -d:release -d:nativeStackTrace
No bug here,refhas no stringification proc. Tree is a ref
@cooldome The problem here is though, that the write(File, Tree) isn't picked up in
for i in x.b:
f.write i
proc foo(args: varargs[string, `$`]) =
echo args
proc foo(i: ref int) =
echo "it's a ref int!"
foo new int
Here's the simplified reproducible example to highlight the bug.
Errors:
Hint: used config file '/playground/nim/config/nim.cfg' [Conf]
Hint: system [Processing]
Hint: widestrs [Processing]
Hint: io [Processing]
Hint: in [Processing]
/usercode/in.nim(7, 9) Error: type mismatch: got <ref int>
but expected one of:
proc `$`(x: bool): string
first type mismatch at position: 1
required type for x: bool
but expression 'new int' is of type: ref int
proc `$`(x: int64): string
first type mismatch at position: 1
required type for x: int64
but expression 'new int' is of type: ref int
proc `$`(x: cstring): string
first type mismatch at position: 1
required type for x: cstring
but expression 'new int' is of type: ref int
proc `$`(x: char): string
first type mismatch at position: 1
required type for x: char
but expression 'new int' is of type: ref int
proc `$`(t: typedesc): string
first type mismatch at position: 1
required type for t: typedesc
but expression 'new int' is of type: ref int
proc `$`[T](x: openArray[T]): string
first type mismatch at position: 1
required type for x: openArray[T]
but expression 'new int' is of type: ref int
proc `$`[T, IDX](x: array[IDX, T]): string
first type mismatch at position: 1
required type for x: array[IDX, T]
but expression 'new int' is of type: ref int
proc `$`(s: WideCString): string
first type mismatch at position: 1
required type for s: WideCString
but expression 'new int' is of type: ref int
proc `$`(x: int): string
first type mismatch at position: 1
required type for x: int
but expression 'new int' is of type: ref int
proc `$`[T: tuple |
object](x: T): string
first type mismatch at position: 1
required type for x: T: tuple or object
but expression 'new int' is of type: ref int
proc `$`(x: float): string
first type mismatch at position: 1
required type for x: float
but expression 'new int' is of type: ref int
proc `$`(x: uint64): string
first type mismatch at position: 1
required type for x: uint64
but expression 'new int' is of type: ref int
proc `$`(w: WideCString; estimate: int; replacement: int = 0x0000FFFD): string
first type mismatch at position: 1
required type for w: WideCString
but expression 'new int' is of type: ref int
proc `$`[T](x: set[T]): string
first type mismatch at position: 1
required type for x: set[T]
but expression 'new int' is of type: ref int
proc `$`[Enum: enum](x: Enum): string
first type mismatch at position: 1
required type for x: Enum: enum
but expression 'new int' is of type: ref int
proc `$`[T, U](x: HSlice[T, U]): string
first type mismatch at position: 1
required type for x: HSlice[$.T, $.U]
but expression 'new int' is of type: ref int
proc `$`[T](x: seq[T]): string
first type mismatch at position: 1
required type for x: seq[T]
but expression 'new int' is of type: ref int
proc `$`(x: string): string
first type mismatch at position: 1
required type for x: string
but expression 'new int' is of type: ref int
expression: `$`(new int)
The bug is caused by the overload of proc write*(f: File, a: varargs[string, `$`]). Currently there is no way to opt out of this overload. My fix to this problem would be to remove this overload, or move it at least to a different module, so that it is possible to opt out of it.
I've tested it, if you remove/comment-out that function, the example works as expected.
https://github.com/nim-lang/Nim/blob/float-more-print-precision/lib/system/io.nim#L379
@alaviss @cooldome @Araq The problem here is @tohl doesn't want to create intermediate string objects. Yet there is currently no way to opt out of intermediate string allocation.
Can we focus on the real problem that a varargs overload take precedence over a ref-based overload?
It's even more interesting when it only seem to affect ref-based overloads. This snippet highlights that: https://play.nim-lang.org/#ix=28zJ [https://play.nim-lang.org/#ix=28zJ]
It seems real problem is not varargs overload take precedence over a ref-based overload.
If there was a overload with varargs[string, abc], you get compile error in case you don't have proc abc even if there is a overload that much your arguments.
proc test(x: varargs[string, abc]) =
echo "test proc with varargs"
type
Foo = ref object
Bar = ref object
proc test(x: Foo) =
echo "test proc takes Foo"
proc test(x: Bar) =
echo "test proc takes Bar"
proc abc(x: Foo): string =
echo "proc abc(x: Foo)"
return "Foo from abc"
# Uncommenting this proc make `test(b)` compile.
#[
proc abc(x: Bar): string =
echo "proc abc(x: Bar)"
"Bar from abc"
]#
var
a: Foo
b: Bar
test(a)
#test(b)
#[
Compile error:
|| /home/jail/prog.nim(24, 6) Error: type mismatch: got <Bar>
|| but expected one of:
|| proc abc(x: Foo): string
|| first type mismatch at position: 1
|| required type for x: Foo
|| but expression 'b' is of type: Bar
||
|| expression: abc(b)
]#
Output:
test proc takes Foo
In this code, proc test(x: Foo) is picked even if there is proc test(x: varargs[string, abc]).
But when I call test(b), I got compile error and it says there is not proc abc that take Bar type argument.
When I define proc abc(x: Bar): string, this code compile without error and proc test(x: Bar) is called.
Closed #13182 via #13345.
thanks for the fix!
looks like it caused https://github.com/nim-lang/Nim/issues/13378 so that PR may have to be reverted unless someone has a better idea..
at least with https://github.com/nim-lang/RFCs/issues/191 we can define echo and write without varargs[string,$] so it'll fix this particular problem.
here's a workaround in meantime:
import system except write
template write(f, a) = system.write(f, a)
# then top-post example works
Most helpful comment
Can we focus on the real problem that a varargs overload take precedence over a ref-based overload?
It's even more interesting when it only seem to affect ref-based overloads. This snippet highlights that: https://play.nim-lang.org/#ix=28zJ [https://play.nim-lang.org/#ix=28zJ]