Skip to content

Instantly share code, notes, and snippets.

@jdmichaud
Created December 13, 2025 10:58
Show Gist options
  • Select an option

  • Save jdmichaud/386a1dbed241a174342f77994ea1051c to your computer and use it in GitHub Desktop.

Select an option

Save jdmichaud/386a1dbed241a174342f77994ea1051c to your computer and use it in GitHub Desktop.
Vectors/Matrices in Zig

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.


1. You’re right about one big thing

“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.


2. Where vectors and matrices are actually the same

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.


3. The actual fault line: 1 index vs 2 indices

This is the point people often fail to articulate clearly.

A vector has:

v[i] -> T

A matrix has:

m[i][j] -> T

This is not about math — it’s about language surface area.

To support matrices as primitives, Zig must decide:

  1. Is m[i] valid?
  2. If so, what is its type?
  3. Is that type addressable?
  4. Does slicing exist?
  5. 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.


4. Why vectors avoided this problem entirely

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.


5. This is why “just do what vectors do” stalls

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.


6. About element-wise multiplication (you’re right again, but…)

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.


7. The distilled difference (no fluff)

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

8. Your position refined (and I think defensible)

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.


9. Final takeaway

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment