I've been using Nim for work and play for a few years, but I'm still stumped what is the "Nim way" to replace our larger projects.
##### The Project This is a scientific simulation C++ OOP modular project with user-contributed compilable plugins (but everything is compiled at the same time, so no runtime loading). What that means is any module may include definitions from any other module to work with that module. We specifically allow tight-coupling between modules should a module designer want to use this. This tight-coupling is quite the problem, otherwise we could enforce abstraction through composition or concepts, so maybe our situation is unique in this respect leading to the awkward solution below ( **3.C** ) ##### 1) Nim supports limited forward declarations The naive approach to replace our project is to mirror the C++ use of forward declarations for type and function information allowing every module to have access to other module's information. But, Nim does not completely allow forward declarations. ##### 2) Nim does not allow cyclic imports Blindly forging ahead with `import` means we run into the cyclic imports problem. ##### 3) Unity / All-In-One builds I often see this as a solution to the 2 previous naive methods: basically put all your code in 1 file. **A)** We could write the entire project in a single (gigantic) file and use the experimental codeReordering. Works! But eww. Asking module developers to "Cut and paste" their code is awful, and losing organization by file is awful, not to mention we lose module-level build caching and must rebuild the entire code all the time. **B)** We can fix the organization problem by using a system of `include` statements to construct an all-in-one file at compile time. However, this does not play nicely with `nimsuggest`* and the developer experience is worse for it, requiring all developers to be expert and have memorized the code base. (* because `nimsuggest` is a static analysis tool so ignores `include` statements) **C)** We can fix the nimsuggest problem by allowing faux modules, where users write a nim file as if they're writing a standard module and `import` all the other plugins or portions of the codebase as needed. However, as pointed out in approach **2** , this will create cyclic imports. To fix this, we use a nimscript build file that preprocesses every file's `import` statements, stripping it of problematic imports, then constructing an all-in-one build file. Thus we get the appearance of forward declarations, the optimization of 1 define across all binary objects, and `nimsuggest` works! But wow, is this hoop-jumping really the "Nim way" for large projects of this nature?... Oh, and we have to rebuild the entire code base every time anything is changes :( . ##### 4) Independent Libraries Model We could force module developers to create entirely independent libraries (let's say static libraries) and if they require other types and functions from other plugins or portions of the codebase, then they have to include that possibly redundant code into their plugin. This would work, but may cause binary bloat - and I'm not even sure the vtables would work out linking the final executable with the multiple definitions. ##### Conclusions? All-In-One build, but must recompile the entire codebase for every change. Or Indipendent Libraries where each module is standalone and must include all code it needs to work, possibly bloating the final executable. ##### Other ideas? I'm so curious to hear your thoughts!