Suppose I want to specialize a generic procedure. Is there any way I can do this in nim right now? Example:
type
Vector[N: static[int]] = array[1..N, float32]
proc `<`*[N: static[int], T](a: array[1..N, T]): Vector[N] =
for i in 1..N:
result[i] = a[i].float32
proc foo*[N](a: Vector[N]): void =
echo "foo generic"
proc foo*(a: Vector[3]): void =
echo "foo 3"
let v: Vector[3] = [1, 2, 3]
foo(v)
output: "foo generic"
A particular example where this is helpful is for defining operators over that Vector type. I would rather define:
proc `+`*[N](a: Vector[N], b: Vector[N]): Vector[N] =
result = 0
for i in 0..N:
result += a[i] * b[i]
proc `+`*(a: Vector[3], b: Vector[3]): Vector[3] =
<[a[0] + b[0], a[1] + b[1], a[2] + b[2]]
than:
proc `+`*[N](a: Vector[N], b: Vector[N]): Vector[N] =
when N == 3:
<[a.x + b.x, a.y + b.y, a.z + b.z]
else:
result = 0
for i in 0..N:
result += a[i] + b[i]
to make a faster version of the + operator for vector3s. (In this example the speed difference may be negligible, but imagine if I'm summing a lot of Vector3s, or if the operator and type were more complicated, like Matrices).
Am I missing a corner case of the language spec, or is this not possible right now?
Indeed I was wondering about a similar problem myself some time ago, but not really serious...
Well, you have defined a generic data type, so the generic proc version is used. My first idea was to move the nongeneric proc above the generic one, in the hope that compiler would pick the first matching one. But that seems to make no difference.
I think what we may really desire is loop unrolling by the compiler for small N. The C/C++ or LLVM backend may do that, maybe later the Nim frontend too. Have you inspected the assembly output for N = 3? Maybe it is already perfect code?
Compiler bug aside, use the for loop version, always. Typo-safe, gets optimized to the same machine code. Check the produced assembler. Embrace science, not superstition.
But the when version is much cleaner than misusing the overloading mechanism for optimizations. Overloading is for compile-time polymorphism, not for optimizations.