File 1:
proc getOpTblEx1*[T] () : seq[tuple[weight:int, min_nary:int, max_nary:int,
set_map:proc(p:seq[HashSet[T]]):HashSet[T]]] =
result =
@[
(1, 2, 0, set_join[T]),
(1, 2, 0, set_meet[T]),
(1, 2, 2, set_diff[T]),
]
when isMainModule:
echo getOpTblEx1[int]()
Error:
op_tbl_ex1.nim(14, 19) template/generic instantiation from here
op_tbl_ex1.nim(7, 5) Error: type mismatch: got (seq[(int, int, int, proc (p: seq[HashSet[system.int]]): HashSet[system.int]{.gcsafe, locks: 0.})]) but expected 'seq[tuple[weight: int, min_nary: int, max_nary: int, set_map: proc (p: seq[HashSet[system.int]]): HashSet[system.int]{.closure.}]]'
How can there be a type mismatch, the two types listed are precisely equal!
I tried replacing the type tuple with just (int, int, int, proc(...)) and still same error.
Here's the minimal example:
proc blah[T](a: T) : int =
return 1
proc getTbl*[T] () : seq[(int, int, int, proc(a: T): int)] =
return @[
(1, 2, 0, blah[T])
]
when isMainModule:
echo getTbl[int]()
And error:
op_tbl_ex1.nim(13, 14) template/generic instantiation from here
op_tbl_ex1.nim(8, 12) Error: type mismatch: got (seq[(int, int, int, proc (a: int): int{.gcsafe, locks: 0.})]) but expected 'seq[(int, int, int, proc (a: int): int{.closure.})]'
check out the {.procvar.} pragma documentation.
blah() and set_join() (I am guessing) need to be identified as able to be passed as a proc variable
@jlp765, yes I made set_join {.procvar.} and still makes no diff in the error.
I will try switching over to a Table instead of a seq and see if the mysterious error goes away.
EDIT: Switched to Table and got the SAME SHITTY ERROR!!!!!!!!! >_<
op_tbl_ex1.nim(14, 19) template/generic instantiation from here
op_tbl_ex1.nim(9, 19) Error: type mismatch: got (Table[system.int, (int, int, int, proc (a: int): int{.gcsafe, locks: 0.})]) but expected 'Table[system.int, (int, int, int, proc (p: int): int{.closure.})]'
Code:
import sets
import std_set_maps
import tables
proc blah[T] (a: T) : int {.procvar.} =
return 1
proc getOpTblEx1*[T] () : Table[int, (int, int int, proc(p: T) : int)] =
result =
toTable(@[
(0, (1, 2, 0, blah[T]))
])
when isMainModule:
echo getOpTblEx1[int]()
The underlying problem is that you are passing in a raw function, but the table expects a closure. For example, the following version of your minimal example works:
proc blah[T](a: T) : int =
return 1
proc getTbl*[T] () : seq[(int, int, int, proc(a: T): int {.nimcall.})] =
return @[
(1, 2, 0, blah[T])
]
when isMainModule:
let t = getTbl[int]()
There are actually a couple of problems with the design (of the language) here. One is that there are mutually incompatible defaults (for procedure declarations vs. procedure types) and the other is that there's no implicit conversion of non-closure procedure values to closure procedure types.
You can do explicit conversion via a macro, e.g.:
import macros
macro wrapClosure*(p: proc): untyped =
let pname = p
let ptype = p.getType
for i in 1..len(ptype)-1:
if ptype[i].kind != nnkSym:
error("closure: all argument types of procedure must be named")
let fn2 = quote do:
(proc() {.closure.} = discard)
var fn = fn2[0][0]
var args = newNimNode(nnkFormalParams)
fn[3] = args
var call = newCall(pname)
fn[6][0] = call
let rtype = ptype[1].typeKind
if rtype == ntyEmpty:
args.add newEmptyNode()
else:
args.add ptype[1]
for i in 2..len(ptype)-1:
let sym = genSym(nskParam, "t" & $(i-1))
args.add newTree(nnkIdentDefs,
sym, ptype[i], newEmptyNode())
call.add sym
return fn
when isMainModule:
import strutils
let p: proc(x: string): int = wrapClosure parseInt
echo p("007")
Thanks, Jehan! However, doing that just took away that error and replaced it with an even more cryptic one!
import sets
import std_set_maps
import tables
proc getOpTblEx1*[T] () : seq[tuple[weight:int, min_nary:int, max_nary:int,
set_map:proc(p:seq[HashSet[T]]):HashSet[T] {.nimcall.}]] =
result =
@[
(1, 2, 0, set_join[T]),
(1, 2, 0, set_meet[T]),
(1, 2, 2, set_diff[T])
]
when isMainModule:
echo getOpTblEx1[int]()
ERROR:
op_tbl_ex1.nim(15, 24) template/generic instantiation from here
c:\nim\lib\system.nim(2330, 21) template/generic instantiation from here
c:\nim\lib\system.nim(2312, 16) template/generic instantiation from here
c:\nim\lib\system.nim(2299, 24) Error: type mismatch: got (proc (p: seq[HashSet[system.int]]): HashSet[system.int])
but expected one of:
system.$(x: int)
system.$(x: int64)
system.$(x: uint64)
system.$(x: float)
system.$(x: bool)
system.$(x: char)
system.$(x: cstring)
system.$(x: string)
system.$(x: Enum)
system.$(x: T)
$.$(x: tuple[weight: int, min_nary: int, max_nary: int, set_map: proc (p: seq[HashSet[system.int]]): HashSet[system.int]])
system.$(x: seq[T])
system.$(x: set[T])
system.$(s: WideCString)
system.$(w: WideCString, estimate: int, replacement: int)
sets.$(s: HashSet[$.A])
sets.$(s: OrderedSet[$.A])
tables.$(t: Table[$.A, $.B])
tables.$(t: OrderedTable[$.A, $.B])
tables.$(t: TableRef[$.A, $.B])
tables.$(t: CountTableRef[$.A])
tables.$(t: CountTable[$.A])
tables.$(t: OrderedTableRef[$.A, $.B])
There are actually a couple of problems with the design (of the language) here. One is that there are mutually incompatible defaults (for procedure declarations vs. procedure types) and the other is that there's no implicit conversion of non-closure procedure values to closure procedure types.
Well since nimcall is converted to closure automatically I don't think the claim of "mutually incompatible defaults" is valid. ;-) The real problem here is that type conversions are not lifted to tuple constructors.