This is a very strong objection — and you’re right to push on it. Let me respond directly to your claim, not by retreating to “nested vectors”, and not by hand-waving about math libraries.
I’ll try to be precise about where matrices really do differ from vectors at the “core representation” level, and where they don’t. The key is that the difference is narrower than people often imply — but it’s still real.
“All this applied to vectors too.”
Yes. Absolutely.
When @Vector was introduced, Zig:
- did not define dot products
- did not define cross products
- did not define geometry meaning
- did not privilege any math interpretation
So the argument “matrices are special because math is controversial” does not hold by itself.
On this point: you’re correct, and many discussions around this proposal are muddier than they need to be.
At the “nail down core representation” level, both share:
| Property | Vector | Matrix |
|---|---|---|
| Fixed-size | ✔ | ✔ |
| Compile-time dimensions | ✔ | ✔ |
| Value type | ✔ | ✔ |
| No heap | ✔ | ✔ |
| Compiler-recognized primitive | ✔ | ✔ |
| LLVM lowering | ✔ | ✔ |
From this perspective, yes — a matrix primitive is a straightforward generalization of a vector primitive.
If the proposal stopped here, extrapolating from vectors is not just reasonable, it’s obvious.
This is the point people often fail to articulate clearly.
A vector has:
v[i] -> TA matrix has:
m[i][j] -> TThis is not about math — it’s about language surface area.
To support matrices as primitives, Zig must decide:
- Is
m[i]valid? - If so, what is its type?
- Is that type addressable?
- Does slicing exist?
- Is the layout observable via pointer arithmetic?
For vectors, all of this was already settled.
For matrices, it is not.
And this is a core-representation question, not a math one.
For @Vector, Zig could say:
“Indexing yields a scalar. Done.”
No intermediate types. No partial views. No ambiguity.
Matrices cannot avoid intermediate structure, even if you avoid math semantics entirely.
Example:
const M = @Matrix(4, 4, f32);
const row = m[2];What is row?
@Vector(4, f32)?- A view?
- A copy?
- Addressable or not?
- Does
&m[2]exist?
This is not a problem vectors had.
Vectors had exactly one projection:
Vector → Scalar
Matrices require at least two:
Matrix → Row → Scalar
Matrix → Column → Scalar (maybe)
Even if:
- you forbid column access
- you forbid slicing
- you forbid views
You still must specify what m[i] means, because Zig indexing syntax already exists.
That single decision locks:
- memory layout
- ABI
- pointer semantics
- interaction with
@ptrCast - interaction with
@memcpy
This is why the proposal stops early: the first extrapolation already commits to too much.
You’re also right that:
“element-wise multiplication is rarely what users want”
This is true for vectors too — yet Zig still defines * as element-wise.
So why is that acceptable for vectors?
Because dimension agreement is trivial:
@Vector(4, T) * @Vector(4, T)For matrices:
@Matrix(4, 3, T) * @Matrix(3, 5, T)This introduces:
- result-type inference
- compile-time dimension algebra
- non-symmetric operands
Even if the answer is “don’t define *”, the presence of this asymmetry affects type rules.
Vectors never had this asymmetry.
Let me strip this to the irreducible core:
Vectors are 1-projection types. Matrices are 2-projection types.
Everything else — math meaning, user expectation, libraries — is secondary.
This single fact is why:
- vectors could be added cleanly
- matrices need more design work even at the representation level
A very reasonable stance — and one you’re implicitly arguing — is:
Zig should accept the same risks it accepted for vectors, and define the minimum viable projection for matrices, even if it commits to row-major and
m[i] -> vector.
That is a coherent and defensible design, and frankly, probably where Zig will end up.
But it is a bigger commitment than vectors were — not because of math, but because of indexing and projection semantics.
You’re right to reject vague claims that “matrices are harder because math”. They aren’t.
They are harder because:
- they introduce an extra axis of projection
- and Zig cannot avoid specifying what that means at the language level
That’s the real difference — and it’s smaller, sharper, and more technical than people usually say.
If you want, I can sketch the absolute minimal matrix design that mirrors vectors as closely as possible, with exactly one new commitment and nothing else.