This occurred to me a couple weeks back but I honestly couldn't see much of a drawback, so I got curious about how it is seen by others.
Theoretically speaking, you can use forward declarations to force a module to implement a proc.
So this is possible:
#moduleInterface.nim
proc x1(y: string)
proc x2(y: int)
#main.nim
include moduleInterface
proc x1(y: string) = echo "implemented x1"
proc x2(y: int) = echo "Implemented x2"
This guarantees me that main.nim implements x1 and x2 with exactly the defined signatures at compile-time. I was already made aware that apparently nobody uses forward-declarations for sort of "interfaces" like that, I just wondered if there are drawbacks to this approach or just better ways to do it.
What I like about using forward-declarations this way is basically:
Does maybe the include syntax cause some fundamental problems that I don't yet see?
The reason why we don't use it for os.nim etc is that it doesn't work well with Nim's effect system. In addition to that, you cannot forward declare iterators, templates and macros.
But yes, the idea has plenty of merit.
Interestingly enough often times I don't actually need a concept in any capacity, it's that the same operation on an identical type is supposed to be performed in N different ways.
Example: Password hashing. The type you operate on is always type Password = distinct string. However how you hash that (with pbkdf2 and sha256, sha512, or you use argon or whatever) is different. That's what I do in nimword.
Same thing in my web-application where I generate entire CRUD endpoint groups based on a norm model. Since they all inherit from norm's Model type you only need to define specific procs based on Model.
Also something I just realized: For me a benefit of that approach would also be that the specs of that interface are explicitly defined and provided in a single, concise overview. And that is something I tend to value a fair bit.