Search code examples
qtnim-lang

`cannot bind another '=destroy'` when compiling nimqml project with nim devel compiler


I am experimenting a bit with nimqml and its example docs. The example I am currently playing around with is example3, which deals with defining QObjects. Strangely enough, when compiling the project with the devel branch of nim (as of 13.11.2022, this is the future version of nim 2) run into this error message during compilation:

.../src/playground.nim(4, 1) template/generic instantiation of `QtObject` from here
.../src/playground.nim(15, 8) Error: cannot bind another '=destroy' to: Contact:ObjectType; previous declaration was constructed here implicitly: .../src/playground.nim(9, 5)

It magically works if I use the nim 1.6.8 compiler to compile the project.

I don't quite see why nim devel aka nim v2 would break things. I've successfully managed to compile projects with dozens of dependencies with nim's devel branch up until now and the devel compiler has been perfectly backwards compatible so far. What is this issue with destructors?

For reference, the code I was trying to compile as per the docs from example 3:

import NimQml

QtObject:
  type Contact* = ref object of QObject
    m_name: string

  proc delete*(self: Contact) =
    self.QObject.delete

  proc setup(self: Contact) =
    self.QObject.setup

  proc newContact*(): Contact =
    new(result, delete)
    result.m_name = "InitialName"
    result.setup

  proc getName*(self: Contact): string {.slot.} = ## <-- The line where everything explodes
    result = self.m_name

  proc nameChanged*(self: Contact, name: string) {.signal.}

  proc setName*(self: Contact, name: string) {.slot.} =
    if self.m_name == name:
      return
    self.m_name = name
    self.nameChanged(name)

  QtProperty[string] name:
    read = getName
    write = setName
    notify = nameChanged

Solution

  • The cause for the issue here is the changes in memory management between nim v1 and nim v2 (aka the current devel branch).

    Nimqml is built for nim v1 and thus assumes the default mememory management option of "refc" being used. Refc does not add any destructor procs or the like to your code in hidden ways. ARC/ORC does and ORC is the new default for memory management in nim v2.

    Luckily this can be easily fixed for nimqml, as refc for memory management is still an option in nim v2. Simply add the following compiler flag to tell the nim compiler to use refc instead of ORC and you're done:

    --mm:refc

    Example:

    nim c --mm:refc src/playground.nim

    In the long run we will have to wait for the nimqml bindings to get an update to support ORC.