Ok this is seriously amazing (coming from a C++ guy). However, one thing I don't like with putting matrix dimensions in templates is that then you can't construct them at runtime. I do understand the obvious - that you can't have both static type checks on all operations and runtime-determined matrix sizes. Though I would kill for a language which would specialise my code at runtime and throw an exception for compilation errors. So you could write, e.g.
template <int m, int n, int l>
Matrix<m, l>
mul(Matrix<m, n> lhs, Matrix <n, l> rhs)
{...impl...}
And then be able to call it like
int m, n, k, l = ... read from file or whatever
Matrix <m, n> m1 = ...;
Matrix <k, l> m2 = ...;
try {
Matrix <int o, int p> m3 = m1 * m2;
// ^ code compiled dynamically
// or loaded from cache, based on
// runtime types of m1 and m2.
// o and p set to the result
// of type inference.
// I could imagine even having
// specialised versions with inline
// assembly for specific dimensions.
} catch (DynamicCompilationException e) {
print("dimensions not compatible");
}
Java could be it, if it had reified generics. You'd create an implementation of Num, or load one from cache, then instantiate the template and attempt to call the mul function.
Or you could abuse the invoke dynamic feature - create specialised functions matrixMultiply$m$n$l and classes Matrix$m$n from some other templating language as needed, then do an invoke dynamic based on type. But this would be very cumbersome to use, I think.
Julia does this at runtime. You can create an arbitrarily sized and typed array and call a function. If no implementation exists specialized for that type, it will automatically compile one using LLVM.
(The function that creates the array will be slower since it's not type-stable, but it can generate a type-stable function that's fast.)
statically checked, but still runtime-determined, matrix sizes can be done in Scala. Doing specialized implementations would require bytecode magic, though.
case class Dim(size: Int)
trait Matrix[X <: Dim with Singleton, Y <: Dim with Singleton] {
def *[Z <: Dim with Singleton](other: Matrix[Y, Z]):Matrix[X, Z] = ???
}
object Matrix {
def apply[X <: Dim with Singleton, Y <: Dim with Singleton](x: X, y: Y):Matrix[X,Y] = ???
}
val x = Dim(100)
val y = Dim(readFromFile(...))
val z = Dim(37)
val A = Matrix[x.type, y.type](x, y)
val B = Matrix[y.type, z.type](y, z)
A * A // compile error
A * B // ok
Comments
Ok this is seriously amazing (coming from a C++ guy). However, one thing I don't like with putting matrix dimensions in templates is that then you can't construct them at runtime. I do understand the obvious - that you can't have both static type checks on all operations and runtime-determined matrix sizes. Though I would kill for a language which would specialise my code at runtime and throw an exception for compilation errors. So you could write, e.g.
And then be able to call it like Java could be it, if it had reified generics. You'd create an implementation of Num, or load one from cache, then instantiate the template and attempt to call the mul function.Or you could abuse the invoke dynamic feature - create specialised functions matrixMultiply$m$n$l and classes Matrix$m$n from some other templating language as needed, then do an invoke dynamic based on type. But this would be very cumbersome to use, I think.
Julia does this at runtime. You can create an arbitrarily sized and typed array and call a function. If no implementation exists specialized for that type, it will automatically compile one using LLVM.
(The function that creates the array will be slower since it's not type-stable, but it can generate a type-stable function that's fast.)
statically checked, but still runtime-determined, matrix sizes can be done in Scala. Doing specialized implementations would require bytecode magic, though.
I believe dependent typing is what you're after. Have you looked at Idris?
http://www.idris-lang.org/example/