EDIT: For example, say you want Python's Walrus operator. You can just do this (although you can often just use a slightly more verbose parenthesized `let` expression):
proc `:=`*[T](x: var T, y: T): T = (x = y; x)
or maybe you want `myvar |= flag` like in C/Python. You can also do that: proc `|=`*[T, U](a: var T, b: U) = (a = a or b)
But both of those could also be templates or macros that get the whole AST, can pick the AST apart, and emit whatever Nim code you actually want.In fact, since Nim has nicely nested scopes & hygienic templates, you can define a bunch of operators in a library `template`, called say `unsafePtrArith` for pointer arithmetic, import that and then make them available in a little sub-scope to your code like:
unsafePtrArith: a += 5
or unsafePtrArith:
b += 4
c += 3In my experience, Nim macros (but not templates) can succumb to verbosity in their implementations because manipulation of the AST is generally imperative and can become quite involved in the details of syntax nodes.
Other than that, with the expressiveness of type definitions in Nim, my experience has been that routines often end up short and dry. Learning to wield helpers such as {.push.} and {.pop.} can be helpful in that regard, just depends on what you’re doing.