timotheecour / Nim

Nim is a compiled, garbage-collected systems programming language with a design that focuses on efficiency, expressiveness, and elegance (in that order of priority).
http://nim-lang.org/
Other
2 stars 0 forks source link

WIP ternary assignment operators #588

Open timotheecour opened 3 years ago

timotheecour commented 3 years ago

draft for https://github.com/nim-lang/RFCs/issues/341#issuecomment-778478879

Should be done IMO.

yes, PR welcome, Proposal 1 is indeed non controversial IMO.

I mean, .= is a ternary operator, if we extend it to specifically other dot operators, then why stop there? Why use operators when you can use names?

you are right, it doesn't make sense to special case dot operators in a assignment rewrite rule .?=; note that we do need some way to have such rewrite rule though, which jsffi and nimpy use, eg in nimpy: https://github.com/yglukhov/nimpy/blob/f2a70275f4fcbe69dabbdc6fdd3497ce39ff8c05/nimpy.nim#L1380

template `.=`*(o: PyObject, field: untyped, value: untyped) = ...

note also that there's no such thing as a ternary operator AFAIK (which may be a good decision as it simplifies the precedence / parsing rules); all there is is unary/binary operators in AST, eg:

import macros
macro deb(a: untyped) =
  for ai in a: echo ai.treeRepr
deb:
  foo.bar = baz
  foo[2] = baz
  foo += baz

as:

Asgn
  DotExpr
    Ident "foo"
    Ident "bar"
  Ident "baz"
Asgn
  BracketExpr
    Ident "foo"
    IntLit 2
  Ident "baz"
Infix
  Ident "+="
  Ident "foo"
  Ident "baz"

later semantic pass attempts rewrite rules involving things like []= or setters (bar=) via overload resolution.

which leads me to a modified proposal 2:

proposal 3 (supersedes proposal 2)

links

scratch below

times: `+=`(t: var Time; b: TimeInterval)

proc `[]=`(a: seq[T], index: int, c: T)
proc `[]=`(a: ptr T, b: T)
n0bra1n3r commented 3 years ago

Compiler noob here, but I've been writing my own macro-powered C++ interop library I'm planning to open-source, and I've been missing features that could be implemented through ternary operators. ?.=(a1, a2, a3: untyped) can't be called like a?.b = c, and it would be cool to be able to define things like cppPointerInstance->field().

Are general ternary operators possible as a generalization of this RFC? I was thinking something like:

macro `<op1><space><op2>`(a1, a2, a3) =
  # generate proc for C++ interop

would be called like

a1 <op1> a2 <op2> a3

where op1 and op2 could be a combination of operator symbols, and the space between them determines the grouping. If op1 and op2 have only 1 symbol each the space could be left out.

It (along with a resolution to <sneaky promotion of issue here>) would make things like the following possible in my library:

# works: C++ partial type declaration DSL (works like TypeScript declarations)
class Model
class Mesh:
  class TransformData

let mesh = make Mesh("Player")
mesh.model = cppnew Model() # works: `.=` generates field at CT as it is accessed
mesh.model->LoadFile("model.gltf") # fails: ternary `-> ()` not implemented
mesh.TransformData.MaxNumJoints = 128 # fails: `TransformData` C++ inner class access due to issue
mesh.render() # works: `.()` generates method at CT as it is accessed