Hi!
I'm writing a router for Karax and want to formalize what a renderer is.
The definition I'm going with is that it's a proc that accepts a Context and returns a VNode.
However, when I define a proc with this exact signature, it won't match.
Here's a minimal isolated example:
import std/tables
import karax/[karaxdsl, kbase, vdom]
type
Context = ref object of RootObj
urlParams: TableRef[kstring, kstring]
Renderer = proc(context: Context): VNode
proc render(context: Context): VNode =
buildHtml(tdiv):
text "This is index"
static:
echo render is Renderer
Running it with karun app.nim emits a false.
https://nim-lang.org/docs/manual.html#procedures-closures
nimcall
is the default convention used for a Nim proc. It is the same as fastcall, but only for C compilers that support fastcall.
closure
is the default calling convention for a procedural type that lacks any pragma annotations.
If I make the signatures really precise then it matches. Is there a reason you need to use is? It still matches fine even without the added pragmas
import std/tables
import karax/[karaxdsl, kbase, vdom]
type
Context = ref object of RootObj
urlParams: TableRef[kstring, kstring]
Renderer = proc(context: Context): VNode {.noSideEffect, gcsafe, nimcall.}
proc render(context: Context): VNode {.noSideEffect, gcsafe, nimcall.} =
buildHtml(tdiv):
text "This is index"
static:
echo render is Renderer
# Even if I remove all the pragmas I added, this still works fine
proc foo(x: Renderer) = discard
foo(render)
Thanks! No I don't need to use is, it's just an example.
The problem is that when I later construct an array of (kstring, Renderer), it won't match a proc that expects an openArray(kstring, Renderer).
Here's a more complete example that doesn't compile:
import std/tables
import karax/[karaxdsl, kbase, vdom]
type
Context = ref object of RootObj
urlParams: TableRef[kstring, kstring]
Renderer = proc(context: Context): VNode
Route = tuple[p: kstring, r: Renderer]
proc render(context: Context): VNode =
buildHtml(tdiv):
text "This is index"
proc foo(r: seq[Route]) = discard
const r = {"/": render}
foo(r)
The error is:
app.nim(22, 4) Error: type mismatch: got <array[0..0, (string, proc (context: Context): VNode{.noSideEffect, gcsafe, locks: 0.})]>
but expected one of:
proc foo(r: seq[Route])
first type mismatch at position: 1
required type for r: seq[Route]
but expression 'r' is of type: array[0..0, (string, proc (context: Context): VNode{.noSideEffect, gcsafe, locks: 0.})]
Unfortunately, I can't fix this my explicitly adding the pragmas or adding``closure`` to the type definition.
const r = {"/": render}
That in an array, not a seq. https://nim-lang.org/docs/manual.html#statements-and-expressions-table-constructor
You may try make it a seq or try proc foo(r: openarray[Route]) = discard
You're right, the syntax is incorrect in the message you're replying to.
But you can see it failing with the proper syntax downstream.
Here's the working version:
import std/tables
import karax/[karaxdsl, kbase, vdom]
type
Context = ref object of RootObj
urlParams: TableRef[kstring, kstring]
Renderer = proc(context: Context): VNode {.noSideEffect, gcsafe, nimcall.}
Route = tuple[p: kstring, r: Renderer]
proc render(context: Context): VNode =
buildHtml(tdiv):
text "This is index"
proc foo(r: openArray[Route]) = discard
const r = {kstring("/"): render}
foo(r)
I'm still not 100% happy with this solution but it works and I'm happy with that for now.
Thanks everybody!