I'm trying to use Nim with Elm. Elm has a port system which can send and receive messages, similar to web workers.
I have this code in the main module:
import ./elm
import ./portMessages
type
State = object
elmProgram: elm.Program
portToElm: elm.SubPort[portMessages.Outgoing]
# Error is with this function
proc newState(
elmProgram: elm.Program,
): State =
return State(
elmProgram: elmProgram,
portToElm: elmProgram.getSubPort("rawSubscribe"),
)
When I try compiling, I get this error message from the compiler:
Error: invalid type: 'SubPort[SubPort.T]' in this context: 'proc (elmProgram: Program): State' for proc
This is the elm
module. The SubPort
type allows T
to be sent through a port.
type
Program* {.importjs.} = ref object of JsRoot
SubPort*[T: JsRoot] {.importjs.} = ref object of JsRoot
# Get a reference to a Sub port (to Elm)
proc getSubPort*[T: JsRoot](
program: Program,
name: cstring,
): SubPort[T] {.importjs: "#.ports[#]".}
This is the 'portMessages' module:
type
OutgoingKind* {.importjs.} = enum
portErrorPopup = 0,
Outgoing* {.importjs.} = ref object of JsRoot
case kind*: OutgoingKind
of portErrorPopup:
msg*: cstring
the type mismatch is because getSubPort("messages")
is still an underspecified generic, as its returntype is SubPort[T]
, which can't be inferred from its parameters.
meanwhile, you've specified that your State
type's member portToElm
has the type SubPort[Outgoing]
The answer should be as simple as:
proc newState(elmProgram: Program): State =
State(
elmProgram: elmProgram,
portToElm: getSubPort[Outgoing](elmProgram,"rawSubscribe")
)
but this still doesn't work because of a compiler bug. The workaround is to use concepts for the generic restriction:
in elm
:
type
Program* {.importjs.} = ref object of JsRoot
IsJsRoot = concept type t
t is JsRoot
SubPort*[T: IsJsRoot] {.importjs.} = ref object of JsRoot
proc getSubPort*[T:IsJsRoot](
program: Program, name: cstring): SubPort[T]{.importjs: "#.ports[#]".}
(I don't understand why SubPort needs to be generic in the firstplace, especially as it's importjs, but that's beside the point)