(This question is mostly about whether this approach makes sense or if there is a vastly easier way.)
For example, when working with 2-dimensional coordinates, I might define:
..code-block:: Nim
type
X = distinct int
Y = distinct int
So that I can't mix up the types by accident, which could happen, if X and Y were just plain int.
So far, so good. But often I'd also like to conveniently do math with such types. So that these lines work:
..code-block:: Nim
let
a : X = X(40)+X(2)
b : X = X(40)+2
assert a == X(42)
assert b == X(42)
(Side-note; should have been a comment in the previous code block, but it seems the forum interprets the leading # as instruction to print the comment as a LARGE TITLE): This must not compile: let c : X = 40 + 2
Currently I achieve this by creating overloads via template.
All the generated procs follow this pattern
..code-block:: Nim
template genImplicitUpconversion*(distinctType, usedProc) =
type
D = distinctType
T = D.distinctBase
proc usedProc (d0, d1: D): D = D(usedProc(T(d0), T(d1)))
proc usedProc (t: T; d: D): D = D(usedProc(t, T(d)))
proc usedProc (d: D; t: T): D = D(usedProc(T(d), t))
(Side-note; inside the template usedProc should be usedProc. But that causes an error about "Message needs to be valid RST! Error: input(49, 38) Error: '`' expected", so I left them out.)
This template is used again in another template that overloads all appropriate symbols (like +,-,*,div or /, ...), so that finally all that is required is:
..code-block:: Nim
X.enableImplicitDistinctUpconversion()
My current implementation works but is less flexible than I would like. Before I dig in and make a proper macro out of all this, I wanted to make sure I'm not missing a relevant language mechanism or feature.
Does this approach makes sense or is there an easier way?
Thank you, this looks indeed helpful.
Regarding code blocks, yeah, I tried to apply them, but got tripped up because I wrote "..code-block:: nim" instead of ".. code-block:: nim".