RFCs
RFCs copied to clipboard
Exporting a `toSeq` overload messes up iterator visibility
# file: main.nim
import sequtils
import tables
# this import messes up the functionality of table iterators
import b
let t = initOrderedTable[int, int]()
let s = toSeq(keys(t))
echo s
# file: b.nim
type
Data*[T] = object
data*: seq[T]
proc toSeq*[T](c: Data[T]): seq[T] =
c.data
Compiling main.nim
results in: Error: attempting to call undeclared routine: 'keys'
. Basically none of the iterators from tables
can be used in a toSeq
context when another module (accidentally) exports an overload of toSeq
.
That's because overloaded procs need to have the same untyped
parameters in the same positions. Documented limitation. sequtils.toSeq
always works then. Don't "accidentically export" a toSeq
.
Having a toSeq
function is the natural choice for any data structure which support "to seq conversion", so this is a rather nasty pitfall. In fact I have been using toSeq
functions in several projects of mine and I always though toSeq
+ iterator visibility is just broken in general because I never could do something like toSeq(key(t))
anywhere. It was only by chance to find the cause...
Wouldn't it be possible to solve the issue by avoiding an untyped
implementation of toSeq
in sequtils
and explicitly implement it for iterators and sized collections (maybe by introducing a concept).
Also I struggle to find the documented limitation and I still can't make sense of the error message here. Apparently the overloading resolution seems to pick the right version of toSeq
here, otherwise I would expect a different error. But why does the compiler complain with attempting to call an "undeclared" routine, which obviously is declared?
Wouldn't it be possible to solve the issue by avoiding an untyped implementation of toSeq in sequtils and explicitly implement it for iterators and sized collections (maybe by introducing a concept).
Certainly.
Apparently the overloading resolution seems to pick the right version of toSeq here, otherwise I would expect a different error. But why does the compiler complain with attempting to call an "undeclared" routine, which obviously is declared?
Because it doesn't pick up the right overload.
Certainly.
Then we should probably go for a typed
solution in the stdlib to avoid the issue. If you don't mind I'll reopen...
Edit: Oh haha, I cannot re-open :).
In fact even the standard library violates the "don't accidentally export a toSeq
" for instance in nre, i.e. this also fails to compile:
import sequtils, tables, nre
let t = initOrderedTable[int, int]()
let s = toSeq(keys(t))
I'm afraid the (current?) limitations of inline iterators make a proper solution very tough :-(.
In fact even the standard library violates the "don't accidentally export a toSeq" for instance in nre, i.e. this also fails to compile
I know.
just hit this bug again; import nre
messes up toSeq.
Wouldn't it be possible to solve the issue by avoiding an untyped implementation of toSeq in sequtils and explicitly implement it for iterators and sized collections (maybe by introducing a concept).
Certainly.
no, unfortunately with the way iterators are implemented in the compiler today, I don't think it's possible to have a toSeq(a: typed)
.
See also https://github.com/nim-lang/Nim/issues/9219
I don't think it's possible to have a toSeq(a: typed)
I think the proposal is to have various overloads of toSeq
- one for iterators and the other ones for specific collections. As far as I can tell, this should work, at the cost of some repetition
This issue has been automatically marked as stale because it has not had recent activity. If you think it is still a valid issue, write a comment below; otherwise it will be closed. Thank you for your contributions.
I think the proposal is to have various overloads of toSeq - one for iterators and the other ones for specific collections. As far as I can tell, this should work, at the cost of some repetition
i don't see how this can work without a compiler change; the problem is the toSeq
overload that takes an untyped param to accomodate for any iterable, eg foo(3)
below.
just hit this bug again;
import nre
messes up toSeq.
for reference, the bug is when toSeq requires an untyped param:
when true:
import sequtils
# import nre # uncomment would give: Error: attempting to call routine: 'foo'
iterator foo(n: int): int =
for i in 0..<n: yield i
echo toSeq(1..2)
echo toSeq([1,2])
echo toSeq(foo(3)) # this is the case broken by `import nre`
- alias + enableif fixes this, see https://github.com/timotheecour/Nim/issues/322
- this warning should be made more precise IMO; not all usages of toSeq are broken, only the one involving an untyped iterable
If you love sequtils.toSeq we have bad news for you. This library doesn't work with it due to documented compiler limitations. As a workaround, use this: