(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: > 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: > 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 * convert parameters to base type if not of `distinctType` * pass converted parameters to `usedProc` * convert that result to `distinctType` > 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: > 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?