I'm trying to implement a fix for https://github.com/nim-lang/Nim/issues/8174 and want to define the following:
in ospaths.nim:
# defined in os.getCurrentDir
proc getCurrentDir(): string
proc absolutePath*(path: string, base: string = nil):string=
if isAbsolute(path): return path
let base2 = if base == nil: getCurrentDir() else: base
return joinPath(base2, path)
However I'm getting: Error: implementation of 'ospaths.getCurrentDir()[declared in lib/pure/ospaths.nim(438, 5)]' expected
How would I achieve that without putting absolutePath in ospaths.nim ?
more generally, how to forward declare (and use) a proc in module A and define it in module B?
Most other languages like C, C++, D allow that.
I don't know with other OS, but I tried your fix and it works ok on Windows.
proc getCurrentDir(): string {.importc: "nos$1".}
proc absolutePath(path: string, base = getCurrentDir()): string =
let newpath = if path == ".": "" else: path
base.joinPath newpath
Btw, what is {.importc: "nos$1".} ?
https://nim-lang.org/docs/manual.html#foreign-function-interface-importc-pragma In the example the external name of p is set to prefixp. Only $1 is available and a literal dollar sign must be written as $$.
I don't know with other OS, but I tried your fix and it works ok on Windows.
if so, there's a serious bug, whether or not there's a link error should be consistent across platforms.
eg:
#ospaths.nim
proc getCurrentDir(): string {. importc:"nos$1".}
proc absolutePath*(path: string, base = getCurrentDir()):string=
if isAbsolute(path): return path
let base2 = if base == nil: getCurrentDir() else: base
return joinPath(base2, path)
import os
import ospaths
# my_test.nim
proc test()=
# if false: echo getCurrentDir() # uncomment to remove link error
echo ".".absolutePath
test()
ld: symbol(s) not found for architecture x86_64
https://nim-lang.org/docs/manual.html#foreign-function-interface-importc-pragma In the example the external name of p is set to prefixp. Only $1 is available and a literal dollar sign must be written as $$.
Oops, I missed this, thanks.
let base2 = if base == nil: getCurrentDir() else: base
You don't have to check whether it's nil or not (also, it's preferred to use isNil() too) because base already defaulted to getCurrentDir()
import os, ospaths
You don't have to import ospaths too because os already exported it.
It should be simply
import os
echo ".".absolutePath
after incorporating some of your comments:
proc getCurrentDir(): string {. importc:"nos$1".}
proc absolutePath*(path: string, base = getCurrentDir()):string=
if isAbsolute(path): return path
return joinPath(base, path)
I think that maybe instead of having to do this importc workaround, a better solution might be to better define what belongs in ospaths.nim vs os.nim. For example, I would think that either getCurrentDir() belongs in ospaths.nim, or absolutePath() belongs in os.nim.
It seems like a problem of separation if both modules need to import functions from each other.
That's a workaround, not a proper solution to the more general case. Oftentimes there is genuine mutual dependency between 2 modules A and B. The approach you're suggesting leads in practice to "reinventing the wheel" (ie duplicating some functionality in both modules) and adds friction (eg moving around parts to a third module A and B depend on, or in your specific suggestion moving getCurrentDir to a place it doesn't belong well: ospaths should ideally not have to deal with filesystem, only string manipulation).
D allows this without headers:
module A;
import B;
...
module B;
import A;
...
C++, C allow it with headers. Almost every modern language supports that in some way or another.
Nim has a module system so should allow doing that in same way as D (even though it compiles to C), but an acceptable workaround in the meantime would be to allow doing that via proc declaration as I was doing above.
Happy to discuss implementation details for how to make this work in Nim, but I don't see why it would not be implementable
While the discussion is derailed from the thread title, I think absolutePath should be written in os module because ospaths already exported from os.
As for which of functions should be in os or which should be in ospaths , since I don't know which is better, so I think that only importing os is acceptable.
Oftentimes there is genuine mutual dependency between 2 modules A and B.
No, if that comes up, you don't have 2 modules, but one module that you want to have 2 namespaces. Arguably. There is no universally accepted definition of a "module" as far as I know.
Anyway, maybe eventually Nim will support cyclic deps, but they are just bad design even if supported well:
https://fsharpforfunandprofit.com/posts/cyclic-dependencies/