I've been trying to dive back into Nim and get used to the differences in the way it works compared to the way I'm used to working in python. Mostly it's been fine, but I came across an awkward problem with iterating through the keys in a table in alphabetical order. A simplified example would be:
import algorithm
import tables
var test = {"b": 3, "a": 5, "d": 6, "c": 42}.toTable
for i in test.keys():
echo i, ": ", test[i]
# This is the pythonic way (ignoring the irritating requirement to always provide a cmp
# function), but it fails with "attempting to call undeclared routine: 'keys'"
for i in sorted(test.keys(), cmp=system.cmp):
echo i, ": ", test[i]
# This works, but seems a bit "fussy" to import an extra module and call an extra proc
# just to be able to use an iterator's output as an openArray. It also took me a **long**
# time to find the function when I was searching the documentation.
import sequtils
for i in sorted(toSeq(test.keys()), cmp=system.cmp):
echo i, ": ", test[i]
Is there a cleaner way of making iterators be usable in places where an openArray is needed?
Also as an aside, what's the reason behind the sort functions not assuming system.cmp if no cmp parameter is specified? This has caught me out countless times when I do:
import algorithm
var arr = [1, 5, 3, 6, 7]
arr.sort() # should be arr.sort(cmp=system.cmp)
echo arr
and getting
Error: type mismatch: got <array[0..4, int]>
but expected one of:
proc sort[T](a: var openArray[T]; cmp: proc (x, y: T): int; order = SortOrder.Ascending)
proc sort[A, B](t: OrderedTableRef[A, B]; cmp: proc (x, y: (A, B)): int)
proc sort[A, B](t: var OrderedTable[A, B]; cmp: proc (x, y: (A, B)): int)
proc sort[A](t: CountTableRef[A])
proc sort[A](t: var CountTable[A])
expression: sort(arr)
I like the fact I can specify a cmp algorithm, but it would be nice to have a sensible default...
You need to use an intermediate array or seq to store the ordered keys.
type
OpcParams* = tuple[name: string, cycles: int, ecc: NimNode, addr_mode: NimNode, impl: NimNode]
OpcTable* = OrderedTable[int, OpcParams]
var opcTable = initOrderedTable[int, OpcParams]()
...
opcTable.sort(proc(x, y: tuple[key: int, val: OpcParams]):int = cmp(x.key, y.key))
Note: an OrderedTable is a table that remembers order of insertion, it's not a SortedTable. sort is only implemented on OrderedTable and there is no SortedTable.
Also as an aside, what's the reason behind the sort functions not assuming system.cmp if no cmp parameter is specified?
What if system.cmd[T] is not defined for T? The default would be missing, so it wouldn't compile even when you don't need the default. (I think.).
We're talking about a function which names system.cmp[T] as a specific default. If that doesn't exist, then the function declaration is flawed, even though you don't use the default.
I guess I'm not being clear. Please look at the following example: