nim-works / nimskull

An in development statically typed systems programming language; with sustainability at its core. We, the community of users, maintain it.
https://nim-works.github.io/nimskull/index.html
Other
273 stars 38 forks source link

Spec - macros, `untyped`, `typed`, macro API #51

Open haxscramper opened 2 years ago

haxscramper commented 2 years ago
saem commented 2 years ago

I think a bunch of the procedure dispatch related to typed and untyped parameters needs to move here. 😅

We'll have topics revisited like that because a layer like macros is advanced impacts a broad section of the language.

krux02 commented 2 years ago

two points:

krux02 commented 2 years ago

How does varargs[untyped] work with named arguments. Specifically in:

macro myMacro(args: varargs[untyped]): untyped =
  discard

myMacro(x = 123)

There are currently two possible interpretations:

Specification needed, the compiler cannot try to do both things at the same time.

Vindaar commented 2 years ago

How does varargs[untyped] work with named arguments.

At least in current Nim it works by giving you a nnkArgslist. Given that it's untyped a CT error would be bizarre. Pretty useful stuff. I use it here: https://github.com/Vindaar/ggplotnim/blob/master/src/ggplotnim.nim#L160

krux02 commented 2 years ago

Neither of this compiles. All of them complain that x isn't an argument.

# at least one argument
macro myMacro1(arg1: untyped; args: varargs[untyped]): untyped =
  discard
macro myMacro2(args: varargs[untyped], body: untyped): untyped =
  discard
myMacro1(x = 123)
myMacro2(x = 123)
saem commented 2 years ago

two points:

  • AST based overloading is not tied to or specialized for macros. It is tied to overload resolution. Therefore it should not be listed in this issue.

I don't believe this works. One of the fundamental lessons from writing the stored us that the is most definitely a logical conceptual progression to the spec. It is not ordered in the way you're suggesting. In fact we went down that path only to raise it doesn't work.

Until macros are introduced overload resolution doesn't need to take into account macros and compile time dispatch on code as data.

So it's the introduction of macros and then interaction between it and dispatch that getting this situation about.

From the bottom up the spec is a very primitive language and then we later on functionality which interacts and revisits some bits. Conversely, from the top down you go from the full language to remove one concept and simplify the design.

  • Personally I think AST based overloading isn't necessary for anything and can be removed from the language.

Maybe I don't get the definition of AST based overloading, but dispatch at various times is very much a thing and we need to work out timing.

krux02 commented 2 years ago

@saem


proc foo(arg: int{nkIdent}) =
  echo "it is an ident"

proc foo(arg: int{nkSym}) =
  echo "it is a sym"

proc foo(arg: int{nkStmtListExpr}) =
  echo "it is a stmt list expr"

proc foo(arg: int{nkExprEqExpr}) =
  echo "it is an assignment"

proc foo(arg: int{nkIntLit}) =
  echo "it is an int"

let abc = 123

foo(abc)
foo(456)
foo(arg = 123)
foo:
  var xyz = 123
  xyz *= 2
  xyz

Ast based overloading. No macros involved.

This thing is pure overload resolution and should be specified there. Of course it affects macros, because overload resolution affects macros.

saem commented 2 years ago

@saem

proc foo(arg: int{nkIdent}) =
  echo "it is an ident"

proc foo(arg: int{nkSym}) =
  echo "it is a sym"

proc foo(arg: int{nkStmtListExpr}) =
  echo "it is a stmt list expr"

proc foo(arg: int{nkExprEqExpr}) =
  echo "it is an assignment"

proc foo(arg: int{nkIntLit}) =
  echo "it is an int"

let abc = 123

foo(abc)
foo(456)
foo(arg = 123)
foo:
  var xyz = 123
  xyz *= 2
  xyz

Thanks for the example that clarifies things.

Ast based overloading. No macros involved.

Macros is short hand for metaprogramming, or more importantly in this case dispatch/call resolution not regarding runtime params and their static types.

This thing is pure overload resolution and should be specified there. Of course it affects macros, because overload resolution affects macros.

Dispatching on AST is not at the same level of abstraction and it shouldn't happen there. AST is not part of the type, the timing of dispatch based on analysis and phasing shouldn't end up mixing these two things up. From a logical implementation perspective the concepts don't build up this way, if someone is building up an implementation with the spec they'd increase conformance and utility as they implemented more, AST overloading gets pushed far down the road again.

It might not be here, but I don't want it in regular overloading either, it's definitely around the time where the AST is being formalized into an API.

krux02 commented 2 years ago

Macros is short hand for metaprogramming, or more importantly in this case dispatch/call resolution not regarding runtime params and their static types.

For me its not. At least when working on the Nim compiler, macro explicitly means evenything that is crated with the macro keyword and transforms the ast using code that is compiled down to the nimvm. Maybe we should harden some terminology here?

Dispatching on AST is not at the same level of abstraction and it shouldn't happen there. AST is not part of the type, the timing of dispatch based on analysis and phasing shouldn't end up mixing these two things up.

My opinion. This AST based overloading shouldn't be a part of the language at all because of this problem. You rarely ever need ast based overloading. If you do, it is probably already code smell. And the same logic can easily be implemented with a macro foo that dispatches on the top level node kind.

From a logical implementation perspective the concepts don't build up this way, if someone is building up an implementation with the spec they'd increase conformance and utility as they implemented more, AST overloading gets pushed far down the road again.

I don't know exactly what you mean here.