Right now the standard library and how it connects to the actual OS primitives 
a mix of different approaches.

Let's look at a few examples. lib/pure/os.nim, sleep
    
    
    proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], 
noWeirdTarget.} =
      ## Sleeps `milsecs` milliseconds.
      when defined(windows):
        winlean.sleep(int32(milsecs))
      else:
        var a, b: Timespec
        a.tv_sec = posix.Time(milsecs div 1000)
        a.tv_nsec = (milsecs mod 1000) * 1000 * 1000
        discard posix.nanosleep(a, b)
    
    
    Run

This is nice example, usually there are more when,elif etc. Here we see that 
**inside** the function there are 'when' switches that then brings in the OS 
dependent stuff. Many functions in the library are like this. Thankfully they 
are often partitioned in one single chunk for each. There are standard 
libraries for other languages I've seen where they have several chunks for the 
same OS, one of types, then some code, then some types again, basically litter 
the the equivalent of Nim's 'when'. This approach is the one I like the least.

Let's look at lib/core/locks.nim
    
    
    proc initLock*(lock: var Lock) {.inline.} =
      ## Initializes the given lock.
      when not defined(js):
        initSysLock(lock)
    
    proc deinitLock*(lock: var Lock) {.inline.} =
      ## Frees the resources associated with the lock.
      deinitSys(lock)
    
    proc tryAcquire*(lock: var Lock): bool {.inline.} =
      ## Tries to acquire the given lock. Returns `true` on success.
      result = tryAcquireSys(lock)
    
    proc acquire*(lock: var Lock) {.inline.} =
      ## Acquires the given lock.
      when not defined(js):
        acquireSys(lock)
    
    proc release*(lock: var Lock) {.inline.} =
      ## Releases the given lock.
      when not defined(js):
        releaseSys(lock)
    
    
    Run

Here we can see that the actual implementation is delegated to *Sys function, 
like tryAcquire calls tryAcquireSys. The OS dependent implementation is then 
found in lib/std/private/syslocks.nim. Here we can see actual implementation 
for each platform which are selected with a 'when' clause. This approach is 
nicer because now we have separated the generic part and the OS dependent part.

Now there is step further you can take with this example and that is why not 
let an OS dependent file implement the functions directly, like tryAcquire. So 
the implementation is just included per module basis depending on you OS. 
Basically, the module would start with
    
    
    when defined(windows)
      import windows/locks.nim
    elif defined(posix)
      import posix/locks.nim # This file selects further when it comes POSIX 
variants
    elif defined(...)
    ...
    else:
    ..
    
    
    Run

Right now the standard library is a mix of everything and I've not seen any 
guidelines which approach the project should take. If there is no document or 
guideline describing this then we will have this mixture of everything. What 
approach should be taken?

Reply via email to