With a type that depends on two generic typevars, the type inference implementation seems to get stuck on a particular binding of the second typevar based on the first... is that expected?
Specifically, for these two sections:
var w = DGraph[int,int]()
let _ = w.add_edges(@[(0, 1, 10), (0, 4, 3), (1, 2, 2), (1, 4, 4)])
var g = DGraph[int,float]()
let _ = g.add_edges(@[(3,4,3.5),(4,5,4.5)])
the second one fails with Error: type mismatch: got <DNode[system.int, system.float]> but expected 'DNode[system.int, system.int]'
If I reverse the sections, I get a similar failure with the got and expected types switched.
However, these work fine following either of the above:
var h = DGraph[uint,float]()
let _ = h.add_edges(@[(3u,4u,3.5),(4u,5u,4.5)])
var k = DGraph[char,int]()
let _ = k.add_edges(@[('s','a',3),('s','c',2),('s','f',6)])
The only thing that distinguishes the failure seems to the type taken on by the first typevar.
Help!?
Thanks.
-- e
Below are more details:
type
DEdge*[K, V] = ref object
fm*: DNode[K]
to*: DNode[K]
weight*: V
DNode*[K, V] = ref object
key*: K
outedges: HashSet[DEdge[K, V]]
inedges: HashSet[DEdge[K, V]]
priority*: V # for algorithms to sort upon
index*: int # for algorithms to store sort position
DGraph*[K, V] = object
# A directed graph of nodes and directed edges
nodes: Table[K, DNode[K, V]]
and
proc add_edges*[K, V](graph: var DGraph[K, V], edges: seq[(K,K,V,)]): seq[DEdge[K, V]] =
for (n1, n2, w) in edges:
result.add(add_edge(graph, n1, n2, w))
proc add_edge*[K, V](graph: var DGraph[K, V], fm: K, to: K, weight: V = 1): DEdge[K, V] =
var n1 = graph.add_node(fm)
var n2 = graph.add_node(to)
result = DEdge[K, V](fm: n1, to: n2, weight: weight)
result.fm.outedges.incl(result)
result.to.inedges.incl(result)
proc add_node*[K, V](graph: var DGraph[K, V], key: K): DNode[K, V] =
The example is missing a bit of proc for reproduction but this compiles for me (though it segfaults at runtime after).
import sets, tables, hashes
type
DEdge*[K, V] = ref object
fm*: DNode[K]
to*: DNode[K]
weight*: V
DNode*[K, V] = ref object
key*: K
outedges: HashSet[DEdge[K, V]]
inedges: HashSet[DEdge[K, V]]
priority*: V # for algorithms to sort upon
index*: int # for algorithms to store sort position
DGraph*[K, V] = object
# A directed graph of nodes and directed edges
nodes: Table[K, DNode[K, V]]
proc hash(x: DEdge): Hash =
discard
proc add_edge*[K, V](graph: var DGraph[K, V], fm: K, to: K, weight: V = 1): DEdge[K, V] =
# var n1 = graph.add_node(fm)
# var n2 = graph.add_node(to)
# result = DEdge[K, V](fm: n1, to: n2, weight: weight)
result.fm.outedges.incl(result)
result.to.inedges.incl(result)
proc add_edges*[K, V](graph: var DGraph[K, V], edges: seq[(K,K,V,)]): seq[DEdge[K, V]] =
for (n1, n2, w) in edges:
result.add(add_edge(graph, n1, n2, w))
var g = DGraph[int,float]()
let _ = g.add_edges(@[(3,4,3.5),(4,5,4.5)])
Note that to avoid potential false inference I would change the add_edge signature from weight: V = 1 to weight = V(1)
Thanks @mratsim -- I'll use your weight = V(1) suggestion.
I'm sorry you had to fill in missing bits... the failing code is here
It fails if you uncomment the test case in dijktra.nim and try nim c -r dijktra.nim
OK, I've boiled it down to this self-contained example:
import hashes, sets, tables
type
DEdge*[K, V] = ref object
fm*: DNode[K]
to*: DNode[K]
weight*: V
DNode*[K, V] = ref object
key*: K
DGraph*[K, V] = object
nodes: Table[K, DNode[K, V]]
proc add_edge*[K, V](graph: var DGraph[K, V], fm: K, to: K, weight: V = V(1)): DEdge[K, V] =
var n1 = DNode[K, V](key: fm)
var n2 = DNode[K, V](key: to)
result = DEdge[K, V](fm: n1, to: n2, weight: weight)
when defined(test1):
block:
var w = DGraph[int,int]()
let _ = w.add_edge(0, 1, 10)
echo w
block:
var g = DGraph[int,float]()
let _ = g.add_edge(3,4,3.5)
echo g
when defined(test2):
block:
var w = DGraph[int,int]()
let _ = w.add_edge(0, 1, 10)
echo w
block:
var g = DGraph[uint,float]()
let _ = g.add_edge(3u,4u,3.5)
echo g
Building with -d:test2 works. Building with -d:test1 yields: Error: type mismatch: got <DNode[system.int, system.float]> but expected 'DNode[system.int, system.int]'
Should I create a github issue or am I misunderstanding something?
Yes please create an issue, thanks for the example. Seems like an instance of too strong type bindings for int.
This RFC covers what Nim type bindings rules are in-depth https://github.com/nim-lang/RFCs/issues/153 but I unlike the examples given there your example is expected to work with the current Nim code.