I may have this problem:
I have module a, which defines type A with private field a and also field v of type b.B And I have module b, which defines type B with private field b and also field w of type a.A
# Module a:
type
A* = object
a: int
v: B
# Module b:
type
B* = object
b: int
w: A
One solution is to create a third module, maybe called types, put both type definitions there and import that module from modules a and b.
But then module a can not access field A.a! So I have to mark field a by a * star to export it. But then module b can also access field a, which was not initially intended.
I think in Modula/Oberon recursive/mutual import was solved by separate definition and implementation modules if I remember correctly.
Solutions: Joining modules a and b, or including one from the other. Or using third module types and exporting all members.
Seems all not really nice. Modules a and b are in this case vertices and edges of a triangulation, in C++ generally defined in separate header files with mutual include.
In some languages we can just declare a type, without defining it, so that compiler knows it is a valid type, but I think Nim does not allow that (forward declaration).
its the main reason nim is useless for me (you can't use it like a normal language in any large-scale project)
https://github.com/zah/nim-package-visible-types this might help but its just as ugly
That's also one thing we're struggling with in Status.
For now we use the 3rd solution, a common datatypes file and assume that code doesn't touch what it is exported for it.
For public API you can choose not to export a type and users will not be able to create or inspect its field (even if those have the export marker). They would still be able to assign it or pass it to one of your proc.
It's not really hard...
# module A
type
RequireB = ref object of RootObj
A = object
fieldBimpl*: RequireB
# module B
import A
type
RealB = ref object of RequireB
B = object
fieldA: A
template fieldB(a: A): RealB = RealB(a.fieldBimpl)
ref object shouldn't be a workaround for recursive imports. That's the bad reason to use a ref type:
"Why do you use a GC? Oh I needed recursive imports."