www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Cheaper compile-time tests

reply "bearophile" <bearophileHUGS lycos.com> writes:
This is from the office of not so useful things. If you try to 
fake dependent types in D you end instantiating many times the 
same template, inflating the binary with little purpose (because 
you are not very interested in the optimizations performed on the 
compile-time-known values). So to help that kind of coding I am 
thinking about something like this:



int foo1( generic int c)(int x) if (c > 5) {
     return c * x * x; // foo body
}
void main() {
     auto r1 = foo1!(10)(15);
}



Its semantics is similar to this, but foo2() doesn't exists in 
the binary:


int foo2__(int c, int x) {
     return c * x * x; // foo body
}
int foo2(int c)(int x) if (c > 5) {
     return foo2__(c, x);
}
void main() {
     auto r1 = foo2!(10)(15);
}



So it's closer to this:


int foo3__(int c, int x) {
     return c * x * x; // foo body
}
void main() {
     enum int c = 10;
     static assert(c > 5, "required by foo");
     auto r1 = foo3__(c, 15);
}


So it looks like a function templated on some value, but you are 
instead calling a normal run-time function that requires the 
first arguments must be known at compile-time, and they get 
verified by template constraints.

So all this is just a way to perform compile-time tests on 
values, avoiding the instantiation of many useless templates. 
Those tests are one of the two halves of the tests of dependency 
of the types :-)

Bye,
bearophile
Apr 16 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
 you end instantiating many times the same template, inflating 
 the binary with little purpose (because you are not very 
 interested in the optimizations performed on the 
 compile-time-known values).
I know you want a simple example: import std.stdio, std.string, std.conv, std.numeric, std.array, std.algorithm, std.traits; template TMMul(M1, M2) { // helper alias Unqual!(typeof(M1[0][0]))[M2[0].length][M1.length] TMMul; } void matrixMul(T, T2, size_t k, size_t m, size_t n) (const ref T[m][k] A, const ref T[n][m] B, /*out*/ ref T2[n][k] result) pure nothrow if (is(T2 == Unqual!T)) { T2[m] aux; foreach (j; 0 .. n) { foreach (k, row; B) aux[k] = row[j]; foreach (i, ai; A) result[i][j] = dotProduct(ai, aux); } } void main() { immutable int[2][3] a = [[1, 2], [3, 4], [3, 6]]; immutable int[3][2] b = [[-3, -8, 3,], [-2, 1, 4]]; enum form = "[%([%(%d, %)],\n %)]]"; writefln("A = \n" ~ form ~ "\n", a); writefln("B = \n" ~ form ~ "\n", b); TMMul!(typeof(a), typeof(b)) result = void; matrixMul(a, b, result); writefln("A * B = \n" ~ form, result); } Here a new matrixMul is instantiated for each size of the input matrices, but this avoids that: void matrixMul(T, T2, generic size_t k, generic size_t m, generic size_t n) (const ref T[m][k] A, const ref T[n][m] B, /*out*/ ref T2[n][k] result) pure nothrow Bye, bearophile
Apr 16 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
 Here a new matrixMul is instantiated for each size of the input 
 matrices, but this avoids that:
 ...
So something like this: import std.stdio; void foo(T, generic size_t n, generic size_t m)(const ref T[n][m] matrix) { foreach (ref row; matrix) for (int i = 0; i < n; i++) writeln(row[i]); } void main() { int[2][3] m = [[10, 20], [30, 40], [50, 60]]; foo(m); } means something like this, that is templated only on T: import std.stdio; void foo(T)(in size_t n, in size_t m, const T* matrix) { for (int j = 0; j < m; j++) { auto row = &matrix[j]; for (int i = 0; i < n; i++) writeln(row[i]); } } void main() { int[2][3] m = [[10, 20], [30, 40], [50, 60]]; foo(m.length, m[0].length, cast(int*)m.ptr); } Bye, bearophile
Apr 16 2012