i see on the Tables manual page that if i want to use a "complex" object as a key i must create a hash proc for it. there is an example there too but i do not understand the parts well enough to understand the whole:
type
Person = object
firstName, lastName: string
proc hash(x: Person): Hash =
## Piggyback on the already available string hash proc.
##
## Without this proc nothing works!
result = x.firstName.hash !& x.lastName.hash
result = !$result
what do i need to do to make a seq[int] for example work as a key? replace x: Preson with x: seq[int] i guess to start? and what about each item of the seq? i loop through them and call x.item[first].hash ... !& ... x.item[last] on them all? is that it?
and what is the !& doing? and the !$result, i am unsure about that too, can't see any documentation explaining it.
thank you very much!
EDIT: i found the !& and !$ procs on the hashes module page so i see now where that code comes from. is says on that page that i would only use these procs if i was implementing "a hash proc for a new datatype." seq[int] i assume is NOT a new data type, so i assume my guess above is now wrong.... so how would i make a seq[int] useful as a key?
UPDATE: i used my own advice, and added
proc hash*[A](x: seq[A]): Hash =
## efficient hashing of arrays and sequences.
for it in items(x): result = result !& hash(it)
result = !$result
to my code and it started working! then i removed the above code to make sure that was the problem, and it still works! strange. at this point i think this must be a pebkac (very likely) and had something to do with wrong types (i am using int64 often and since it is not the default i have to be careful). i think i will just use int from now on. just for the record, this code now works as i expected it to:
import tables
var seqtable = initTable[seq[int], seq[int]]()
var blah = @[1,2,3]
var plah = @[4,5,6]
echo seqtable.mgetorput(blah, plah)
lib/pure/hashes.nim defines a hash for an openArray of anything, and a seq is definitely the most common openarray. The initial issue was that you were mixing distinct though sort of equivalent integer types. Making the type inferred seqs seq[int64] would also have worked:
import tables
var seqtable = initTable[seq[int64], seq[int64]]()
var blah = @[1'i64, 2'i64, 3'i64]
var plah = @[4'i64, 5'i64, 6'i64]
echo seqtable.mgetorput(blah, plah)
Also, in Nim you can in-place modify a sequence. If you do this to a key after putting it into the hash table then you can corrupt subtly the table. (The modified key will most likely no longer be in the correct slot of the array). It could all be fine in your eventual code..just warning about a subtle gotcha.
There is also a standard fixed length array which might suit you well. Personally, I think there is a bit of a gap in the standard Nim type setup for a "read-only yet run-time sized array" that can be an instance of openArray. That would be a safer key type for situations close to this.
First of all, I apologise for resurrecting a 4 year old thread.
@britto
Thank you for documenting your approach and how you succeeded with it. Indeed, your solution works still in 2020.
It even works when using the Table[seq[int], seq[int]] as the result type of a proc.
The only downside is, that the table has to be initialised manually, or at least I didn't see a way of using the implicit initialisation with this method you described.
Taken from https://nim-lang.org/docs/tables.html#initTable:
Starting from Nim v0.20, tables are initialized by default and it is not necessary to call this function explicitly.
Not sure what you tried or with which Nim version but this works for me on Nim-0.20.2, Nim-1.2, the head of the devel branch, etc.:
import tables
var seqtable: Table[seq[int64], seq[int64]]
var blah = @[1'i64, 2'i64, 3'i64]
var plah = @[4'i64, 5'i64, 6'i64]
discard seqtable.mGetOrPut(blah, plah)
echo seqtable