I'm discovering Nim and I'm in the learning phase reading the documentation. 
I'm impressed by the language that combines elegance and power, without 
sacrificing security. But I've strange feeling regarding the use of pragmas in 
Nim. This preamble is to justify my naive view of the language and the 
following comment.

According to the [documentation](http://nim-lang.org/docs/manual.html#pragmas), 
"Pragmas are Nim's method to give the compiler additional information / 
commands without introducing a massive number of new keywords. Pragmas are 
processed on the fly during semantic checking. Pragmas are enclosed in the 
special `{.` and `.}` curly brackets. Pragmas are also often used as a first 
implementation to play with a language feature before a nicer syntax to access 
the feature becomes available."

So one can see pragmas in Nim as temporary syntax before definite language 
syntax but also as compiler directives. And according to 
[Wikipedia](https://en.wikipedia.org/wiki/Directive_\(programming\)), 
"Directives are not part of the grammar of a programming language, and may vary 
from compiler to compiler".

Analyzing how pragmas are used in Nim, from the documentation and some source 
files from the compiler, I can extract the following taxonomy:

  * Nim Pragmas
    * Pure pragmas: hints to the compiler/linker with no semantic effects on 
the source code. A different compiler could decide to not support the pragma 
and give the same results. [`noInit, requiresInit, deprecated, noReturn, 
acyclic, shallow...`]
    * Semantic or syntax effects pragmas: these don't respect the pragma rule 
(no side semantic effect to the source code)
      * Syntax pragmas: Change the semantic of the source code. The compiler 
**must** respect these pragmas.
        * Core language [`global, discardable, borrow, raises, tags, 
compileTime, ...`]
        * OOP [`final, base, inheritable, ...`]
        * Concurrency [`thread, threadvar, guard, locks, ...`]
        * Templates
      * Foreign language interfaces [`union, packed, importC, exportC, 
importCpp, importObjC...`]
      * Debug [`breakpoint, watchpoint, debugger, profiler...`]



For instance, why introduce `{.pure.}` with enums to require full 
qualification? If the compiler does not respect the pragma, there are syntax 
errors in the code. Typing and naming should be enough to avoid enums names 
clashes.

Another example with `{.procvar.}` used to qualify a proc that can be passed to 
a procedural variable. This should be the default or the compiler should deduce 
it from analyze of the source, shouldn't it?

Or the `{.global.}` to qualify a global variable or `{.borrow.}` to borrow code 
from overloaded proc.

An important set of pragmas is used for foreign functions interfaces, importing 
headers or injecting code. Why not define a domain specific sublanguage to 
manage this?

I suspect that this pragmas abuse is related to the fact that a macro statement 
can be called using a pragma. That's a simpler way to extend the language 
syntax without touching the compiler and doing tests. But this large amount of 
semantic pragmas is breaking the simplicity of the language. And one can't 
always replace a pragma by a macro statement:
    
    
    compileTime:
      proc compile(code: string): NimNode =
    

is not a replacement for 
    
    
    proc compile(code: string): {.compileTime.} NimNode =
    

and gives a syntax error...

There are 11488 lines containing pragmas of all kinds in the compiler for 
199605 non-empty lines, meaning that almost 6% contain pragmas. For comparison, 
comments represent 19%. So pragmas have a big place in the language.

Am I misunderstanding how pragmas are used in Nim? Is there a model logic 
behind all these pragmas? And will these "syntax" pragmas replaced by language 
keywords before version 1.0?

Thanks

\--

Pierre

Reply via email to