Variadic generics and Tensors

Hello,

I’m currently working on Crystal bindings for AI libraries like Llama.cpp using Vibe Coding.

While doing this, I started thinking about how to build a matrix or tensor library in a statically typed language like Crystal. I began to feel that Variadic Generics might play an important role.

I came across this idea through PEP 646 in Python and a discussion on Hacker News, which show how array shapes (or dimensions) can be expressed and checked at the type level during compilation.

For example, it would be helpful if Crystal could support type signatures like this:

def dot(a : Tensor(Float64, *X, Y), b : Tensor(Float64, Y, *Z)) : Tensor(Float64, *X, *Z)

This kind of typing could help catch shape mismatches at compile time in tensor operations.

There is already an open issue related to this: #7101, but it doesn’t seem to be getting much attention at the moment.

I’m not sure if this idea is really the best approach. In fact, combining static and dynamic typing—like in Python’s NumPy or Ruby’s NArray—might be a more practical solution in many cases, rather than introducing more complexity into the compiler.

Still, I wanted to share this in case it’s useful, and I’d really appreciate hearing thoughts from others who are more experienced or interested in this area. Thank you.

(Translation from Japanese by ChatGPT)

I think that compile-time size is useful for mactrices 3*3 or 4*4 and almost useless for bigger matrices. Compiler won’t optimize 1024 size any different from 2048 and you will need to recompile program to process 1024*768 images instead of 640*480. So if size is given at runtime, it have to be checked at runtime, not with generics but with usual methods.


On the other hand, there are a lot of cases when some dimensions are fixed at compile time and other are given at run time. This will be more complex then just simple tuple of ints but very useful. I’ve tried to do it some time ago: GitHub - konovod/multiarray (lack of variadic generics was solved like this:

private macro declare_macro_array(n)
class MultiArray{{n}}(T, 
  {% for i in 1..n %}
    N{{i}},
  {% end %}
  )
...
declare_macro_array(1)
declare_macro_array(2)
declare_macro_array(3)
declare_macro_array(4)
declare_macro_array(5)
declare_macro_array(6)

)

1 Like