Hey folks,
I'm trying to borrow the [] function for a distinct seq, but not having much luck. Here is what I'm trying to do, boiled down:
type MySeq* {.borrow: `[]`.} [T] = distinct seq[T]
let points = MySeq(@[ (x: 1, y: 2), (x: 5, y: 6) ])
echo points[0]
The compiler error I'm getting is:
test.nim(5, 12) Error: type mismatch: got (MySeq[tuple[x: int, y: int]], int literal(0))
but expected one of:
system.[](a: array[Idx, T], x: Slice[system.int])
system.[](s: string, x: Slice[system.int])
system.[](a: array[Idx, T], x: Slice[[].Idx])
system.[](s: seq[T], x: Slice[system.int])
Thanks in advance for any help you can offer
In the manual it says: http://nim-lang.org/manual.html#distinct-type
The borrow pragma can also be used to annotate the distinct type to allow certain builtin operations to be lifted:
type
Foo = object
a, b: int
s: string
Bar {.borrow: `.`.} = distinct Foo
var bb: ref Bar
new bb
# field access now valid
bb.a = 90
bb.s = "abc"
Currently only the dot accessor can be borrowed in this way.
I'm not sure why a normal borrow doesn't work, maybe it has to do with [] being special for seqs:
proc `[]`*[T](a: MySeq[T], x: int): T {.borrow.}
So you have to do this instead:
proc `[]`*[T](a: MySeq[T], x: int): T = seq[T](a)[x]
I'm not entirely sure why it doesn't work, but the indexing operator for arrays, sequences, etc. gets special treatment in the compiler for a number of cases and isn't actually defined in system.nim. For example, constant folding is done if the seq or array is constant, and tuple indexing also requires special treatment (where the index has to be a constant).
My recommendation would be to overload it with either an {.inline.} proc or with a template so that the operation can be properly inlined. E.g.
proc `[]`*[T](s: MySeq[T], i: int): T {.inline.} = seq[T](s)[i]
Constructing a template is more difficult, since we can't access type parameters in the template body, but there's a workaround:
# We don't actually call this procedure, we just need it for
# the type inference of the actual template.
proc toSeqProc[T](s: MySeq[T]): seq[T] {.inline.} = seq[T](s)
# Actual template to convert MySeq to seq without knowing T.
template toSeq[T](s: MySeq[T]): seq[T] =
type SeqT = type(toSeqProc(s))
SeqT(s)
template `[]`*[T](s: MySeq[T], i: int): T = toSeq(s)[i]