Search code examples
genericshashtablenim-lang

nim two key table with generics


Trying to create a two key dictionary in Nim where where the value is a user specified type.

import Tables

type
  TwoKeyTable[T] = Table[string, Table[string, T]]

# initialize two key table
proc initTwoKeyTable[T](): TwoKeyTable[T] =
  result = initTable[string, Table[string, T]]()  

# check to see if keys k1 and k2 are in table
proc hasKeyPair[T](tkTable: TwoKeyTable[T], k1, k2: string): bool =
  result = false
  # check if first key is in table
  if not tkTable.hasKey(k1):
    return
  # check if second key in the tables
  if not tkTable[k1].hasKey(k2): # 1st error coming from here 
    return
  result = true

# add a value corresponding to the keys k1 and k2
proc addKeyPairValue[T](tkTable: var TwoKeyTable[T], k1, k2: string, val: T) =
  if not tkTable.hasKey(k1):
    tkTable[k1] = initTable[string, T]() # 2nd error coming from here
  tkTable[k1][k2] = val


var tkTable = initTwoKeyTable[int]()
echo tkTable.hasKeyPair("a", "b") # produces the 1st error

Which gave the following error:

lib/pure/collections/tables.nim(249, 38) Error: type mismatch: got (Table[system.string, system.int]) but expected 'int

I also have a problem with this.

var tkTable = initTwoKeyTable[int]()
tkTable.addKeyPairValue("a", "b", 1) # produces the 2nd error

Which gives the same error.


Solution

  • Looks a lot like a bug to me, I reported it: https://github.com/nim-lang/Nim/issues/2722

    As a workaround it works when TwoKeyTable is not generic:

    import Tables
    
    type
      TwoKeyTable = Table[string, Table[string, int]]
    
    # initialize two key table
    proc initTwoKeyTable(): TwoKeyTable =
      result = initTable[string, Table[string, int]]()
    
    # check to see if keys k1 and k2 are in table
    proc hasKeyPair(tkTable: TwoKeyTable, k1, k2: string): bool =
      result = false
      # check if first key is in table
      if not tkTable.hasKey(k1):
        return
      # check if second key in the tables
      if not tkTable[k1].hasKey(k2): # 1st error coming from here
        return
      result = true
    
    # add a value corresponding to the keys k1 and k2
    proc addKeyPairValue[T](tkTable: var TwoKeyTable, k1, k2: string, val: T) =
      if not tkTable.hasKey(k1):
        tkTable[k1] = initTable[string, T]() # 2nd error coming from here
      tkTable[k1][k2] = val
    
    
    var tkTable = initTwoKeyTable()
    echo tkTable.hasKeyPair("a", "b") # produces the 1st error