I realize that there is or should be a feature freeze pending the release of Nim 1.0, so this is a feature proposal for whatever comes after.
One of the interesting things about D's templates is the ability to parameterize over a code block, not just a type or function. I think this feature or something like it would fit well with Nim (obviously using the new keyword generic and not template), and provide a bit more expressive power to the generic system.
I'd be interested in what other Nim users think. I wanted to have such a feature when I was experimenting with a hand rolled OOP for Nim.
I'm referring to the ability of D templates beyond the ability to write function or struct class templates, but templates over blocks that include new types and variables, almost like the parameterized module system of OCaml. Forgive me for writing D here, I'll translate it to Future Nim soon ;-)
As with C++ D has function templates like so
void copy(T)(out T to, T from) {
to = from;
}
T sum(T)(T lhs, T rhs) {
return lhs + rhs;
}
and struct/class templates like
struct Node(T) {
T v;
Node* left;
Node* right;
}
but D has a general code block template, in which you can declare variables and new types, like
template MyTemplate(T) {
T val;
void copy(out T to, T from) {
to = from;
}
struct Node {
T v;
Node* left;
Node* right;
}
}
In D the function and struct templates are special cases of the more general code block syntax, but that's not important. What's important to me is that it is like a parameterized module, so I can declare variables in there.
I'm obviously not that good at explaining things. Here's a bit more D, to flesh out the example
import std.stdio;
template MyTemplate(T) {
T val;
void copy(out T to, T from) {
to = from;
}
struct Node {
T v;
Node* left;
Node* right;
}
}
int main() {
writefln("hello world\n");
MyTemplate!(int).val = 666;
MyTemplate!(string).val = "Hello";
writefln("val = %d and val = %s\n",
MyTemplate!(int).val,
MyTemplate!(string).val);
MyTemplate!(int).copy(MyTemplate!(int).val, 42);
writefln("val = %d and val = %s\n",
MyTemplate!(int).val,
MyTemplate!(string).val);
return 0;
}
(calling again with the same type param does not create a new code block)
This doesn't seem good idea.
Do not confuse the word template in D with the same word in Nim, they are not the same thing at all. Perhaps that's why there's such misunderstanding, and why the proposed solution didn't even come close to doing what the D template I wrote does?
I referred to ML modules in my description above, and that behavior of not creating a new code block with the same type param is similar to applicative functors (OCaml) vs generative functors (SML). For OCaml experts, yes I know that OCaml has supported both for a while.
In any case, D uses this stuff to good effect, and there seems to be no straightforward way to model the salient aspects of D templates as code blocks in Nim. What they are providing is a generic (in the Nim sense) scope which can be referred to elsewhere. In D I can alias an instantiation to a shorter name, but I didn't demonstrate that. What I did show is that you can instantiate multiple ones in the same scope, refer to them, and refer to their internal variables.
If you want to compute a value at compile-time you can use a static block that returns a tuple and you can extract what you need from that tuple.
Or you can use a template + inject like what we're doing here: https://github.com/status-im/nimbus/blob/master/nimbus/vm/interpreter/gas_costs.nim#L112