digitalmars.D - Cheaper compile-time tests
- bearophile (42/42) Apr 16 2012 This is from the office of not so useful things. If you try to
- bearophile (37/41) Apr 16 2012 I know you want a simple example:
- bearophile (31/34) Apr 16 2012 So something like this:
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
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
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