Hello, I have a small feature proposal that I didn't feel comfortable making an 
RFC for.

**Synopsis**

Introduce a "wrap" statement which is allowed only on top-level code. `wrap X` 
replaces the AST of the entire program on all following lines with the result 
of passing it through the macro `X`.

**Example**
    
    
     # a.nim
    macro implementRecur(n: untyped): untyped =
      ## Allows functions to refer to themself by calling ``recur()``
      ## To suppress this behavior, annotate the function with 
``{.literalRecur.}``
      ...
    
    
    Run
    
    
    # b.nim
    import a
    wrapwith a.implementRecur
    
    proc factorial(n: int): int =
      if n == 0:
        return 1
      return n * recur(n - 1)
    
    proc funky(): bool {.literalRecur.} =
      let recur: bool = false
      return recur
    
    
    Run

**Rationale**

1\. Redundancy

Currently, the most typical way to implement a macro similar to 
`implementRecur` would be to implement a `recursive` macro which operates on 
function definitions. Then, all function definitions that want to reap the 
benefits of this behavior must be annotated with `{.recursive.}`.

To me, this feels redundant. I don't want to have to say "hey, I'm using the 
`recur` keyword over here"" every time I use the `recur` keyword; it should be 
obvious by the fact that I'm _using the ``recur`` keyword_.

_Post-script_ : But, okay, what if I actually meant to refer to a variable 
named `recur`? That's what `{.literalRecur.}` is for. You have to annotate one 
case or the other; it would be nice to annotate the (likely) rarer one (in this 
case, `literalRecur`). If referring to `recur` literally is more common in a 
use-case, don't use wrapwith and instead annotate each function.

2\. Bridging the gap between macro classes

Consider the `=>` macro from `sugar`. It requires no special annotation or 
extra code in order to use; the macro itself is enough. Why? Because Nim 
happens to provide sufficient tools for it to work (namely, `auto`). Should 
these tools not have existed, `=>` would need an annotation much like 
`implementRecur` or `{.recursive.}`.

I posit that the reason the example recur macro _does_ need annotation is 
simply because Nim happens to not supply enough tools for it to do its job. If, 
for instance, macros had the power to traverse up the AST as well as down, 
`implementRecursive` and `{.recursive.}` wouldn't be needed; a `macro 
recur(ast: untyped): untyped)` would be sufficient.

Noting this, I claim that these two macros are of "equal conceptual power". 
That is, they work on a similar enough level that I claim that _neither_ should 
require annotation.

Now, the example recur macro _does_ need annotation, the best we can do is to 
make it as unobtrusive as possible. This is what `wrapwith` is about.

3\. Equal power to existing constructs

This proposal does not add any novel behavior to the language. `wrapwith X \n 
restOfCode` may be currently written instead as `X: \n\t restOfCode`. Since no 
novel behaviour is added, the proposal can (in some sense) be considered fairly 
safe.

4\. Git diff

Removing or adding a DSL will no longer require a change in indentation, which 
is much nicer for VCS.

**PostScript**

I've had some trouble reifying my thoughts here, largely because a lot of the 
reason that I think this should be a feature is simply because it "feels right" 
to me. Arguments 1 & 2 are somewhat philosophical and perhaps poorly explained. 
If so, I apologize, and they may be ignored.

Reply via email to