In my rather large project, I'm running into trouble with code organization and circular imports. I've reduced my actual problem down to the simplification below, but a high level description is: I have my main set of code for working with files (foo.nim). I've written separate modules to do different things related to those files. I kind of think of them as plugins to the main code. And each "plugin" might require some initialization in the main chunk of code.
For the most part, the modules don't depend on each other or the main file. However, in my latest module (bar.nim), it needs some stuff defined in foo.nim (pause and resume).
# objs.nim
type
App* = object
files*: seq[MyFileHandle]
MyFileHandle* = object
app: App
path*: string
# foo.nim
import ./objs
import ./bar
proc pause*(fh: MyFileHandle) =
fh.app.files.delete(fh.app.files.find(fh))
proc resume*(fh: MyFileHandle) =
fh.app.files.add(fh)
proc openFile*(app: App, filename: string): MyFileHandle =
result.path = filename
result.initialize_bar()
result.resume()
# bar.nim
import ./objs
import ./foo
proc initialize_bar*(fh: MyFileHandle) =
discard "something bar-related"
proc somebarfunc*(fh: MyFileHandle) =
fh.pause()
discard "do stuff"
fh.resume()
So now foo.nim uses stuff from bar.nim and bar.nim needs stuff from foo.nim.
One solution is to combine the two files. But I don't love that because it will mean foo.nim gets gigantic and eventually contains everything
Another solution is to put pause and resume in a different file that both foo.nim and bar.nim import, but then I have to come up with a name for that and I've split the code out not because of a logical subject-related reason, but to satisfy circular imports.
Any better options?
Delayed imports are your friend:
# objs.nim
type
App* = object
files*: seq[MyFileHandle]
MyFileHandle* = object
app*: App
path*: string
func `==`*(a, b: MyFileHandle): bool = # Some Nim `==` func issue
a.app == b.app and a.path == b.path
# foo.nim
import ./objs
proc pause*(fh: var MyFileHandle) =
fh.app.files.delete(fh.app.files.find(fh))
proc resume*(fh: var MyFileHandle) =
fh.app.files.add(fh)
import ./bar
proc openFile*(app: var App, filename: string): MyFileHandle =
result.path = filename
result.initialize_bar()
result.resume()
# bar.nim
import ./objs
proc initialize_bar*(fh: MyFileHandle) =
discard "something bar-related"
import ./foo
proc somebarfunc*(fh: var MyFileHandle) =
fh.pause()
discard "do stuff"
fh.resume()