Nim: write requires conversion to string

Created on 17 Jan 2020  路  9Comments  路  Source: nim-lang/Nim

write requires conversion to string

hmm, I think this is a bug

Example

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

Current Output

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

Expected Output


Possible Solution

s/write/mywrite fixes the example

but i would expect that my write method would be used

Additional Information

$ 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

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]

All 9 comments

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
Was this page helpful?
0 / 5 - 0 ratings