I'm running into this problem in every project of mine, and I simply can't find a good solution, although the problem seems very basic.
Let's say I write a dummy `lib.nim` like this: # The lib provides a definition of an abstract base type # without any actual instantiations... type Element* = ref object of RootObj # Example for a field that should be an implementation # detail, used only internally in `lib`. It should # neither be public nor should there be getter/setter # so that we can rely on the fact that it does not # change after construction. id: string proc run*(elements: openarray[Element]) = for element in elements: echo "Touching element: " & element.id Run The library is intended to be instantiated on user side, for example: import lib type ElementA = ref object of Element ElementB = ref object of Element # But how to construct them? proc newElementA(): ElementA = ElementA(id: "A") proc newElementB(): ElementB = ElementB(id: "B") let elements = @[ newElementA().Element, newElementB(), ] run(elements) Run This doesn't compile because the user has no access to `id` at all, even in the constructor. Usually I provide a constructing proc in the scope of the type, e.g.: # in lib.nim proc newElement*(id: string): Element = Element(id: id) Run Now users can construct an `Element`, but I'm not sure if it helps constructing subtypes. This crashes at runtime with an invalid conversion (kind of expected): proc newElementA(): ElementA = result = newElement("A").ElementA Run I also don't want to add setter procs/templates to `lib.nim` because than the field gets fully exposed. Am I missing some basic template/macro tricks to solve this basic problem? I have spend hours going back and forth making fields private and public again or moving code around because I can't seem to get the visibility right.