Currently in the C++ code I have written for field algebra dimension (mass, length, time, temperature, moles, luminous intensity and current) checking is performed at run-time mainly because the time I wrote it predates templates by a few years. Now it is possible using integer template arguments to perform this dimension checking at compile time but it is very complex, messy and the error messages would be unintelligible. Maybe with "concepts" it would have been easier, well at least the error messages would have been better, but will this ever be included in the standard?
In Nim it may be possible to use the "concepts" mechanism for this compile time checking but I was wondering if the effects/tags mechanism could be enhanced to make this easier? Basically types would need to be tagged with the constant integer values corresponding to the dimensions of the type and comparison functions executed at compile time on this information. Or maybe macros could be used to lookup the dimensions of a type from a constant table and analyze them?
Any thoughts on what might be the best approach to handle this kind of compile-time checking?
> So the basic requirement is to be able to "tag" the types with these integer values and retrieve them in a convenient way.
I might be missing something obvious, but based on this description would something like the following work?
type
Vector[T; Tag:static[int]] = object
x, y, z: T
proc foo[T; Tag:static[int]](v:Vector[T,Tag]): T =
when Tag < 2:
(v.x + v.y + v.z)
else:
(v.x + v.y + v.z) * Tag
let
a = Vector[float,1](x:1, y:2, z:3)
b = Vector[float,3](x:1, y:2, z:3)
echo foo(a) # prints '6.0'
echo foo(b) # prints '18.0'
Here Tag is just used to distinguish, at compile-time, between types of equivalent runtime structure; it's not actually used by the type. Unfortunately it doesn't seem macros.getType is able to evaluate these constants (at least not in any way I'm aware of), but since foo (or any proc/template) can pick them up you can still use them with concepts, eg:
type
Matrix[T; Tag:static[int]] = object
x, y, z: Vector[T,Tag]
template checkMatrix[T; Tag:static[int]](m:Matrix[T,Tag], V:static[int]): bool =
Tag < V
type
SomeMatrix[V:static[int]] = concept m
m is Matrix
checkMatrix(m, V)
proc bar(m:SomeMatrix[2]): string =
"Took the Red Pill"
let
m = Matrix[float,1]()
n = Matrix[float,3]()
echo bar(m) # prints 'Took the Red Pill'
echo bar(n) # compile-time error (n is not SomeMatrix[2])
NOTE: Currently there appears to be a bug with using static[int] and concepts, which is why I've used SomeMatrix[2] in bar instead of making that procedure generic as well.