Type of empty matrix in Rust

George Shuklin
journey to rust
Published in
2 min readAug 30, 2022

Let’s talk about two dimensional matrices in Rust. To be precise, two-dimensional matrices written as nested arrays.

A simple 2x2 matrix is looks like this:

let matrix = [[1, 2], [3, 4]];

A simple 1x1 matrix looks like this:

let matrix = [[1]];

The empty (0x0) matrix is…

let matrix = [[]];

Is it so? Let’s think together. For 0x0 we need to have matrix.len() to be 0. But our ‘outer’ array has length of 1.

So we need to convert it to …

let matrix = [];

But this is one-dimensional array!

And if you try to compile it, Rust will complain:

error[E0282]: type annotations needed for `[[i32; _]; 0]`

Which is, actually, incorrect, because of ‘error[E0658]: using `_` for array lengths is unstable’. It looks like a bug in Clippy.

Anyway, the proper type is [[i32;0];0]:

let matrix: [[i32;0];0] = [];

Which is blowing my mind. It’s completely sound: we need to specify to inner type for the array.

But it’s still blow my mind. If it was foo:[i32;0] = [] no one would complain about specifying a type for an absent element.

But we need to specify inner type for absent value of array type. It’s an empty array of empty arrays of type i32. Huh.

It’s like saying that 3 ≡ {{}, {{}}, {{}, {{}}}}, if you get the joke. Nope, it’s even emptier than that. It’s like saying that 3 ≡ {{{{}}}}. Is it smells of λs here?

The second thing which strikes me, is that we have the singular value for the empty 0x0 array, because only [] is possible value for the type [[i32;0];0].

I become math-immune compromised person, because it smells Zermelo. Or it’s Fraenkel? Actually, no, it’s even more funnier, because I can declare 0≡[], and 1≡[] , and 2≡[] , and 3≡[], and all of them would be differently typed [], because of:

let zero: [i32;0] = [];
let one: [[i32;0];0] = [];
let two: [[[i32;0];0];0] = [];
let three: [[[[i32;0];0];0];0] = [];

Unfortunately, we can’t do math… Or can we? Some kind of recursion? I believe it’s not possible with lambdas, and any function would require signatures which can work with const generics, but not with ‘recursion depth’.

let sum = (|A, B|{[]})(one, two);

Nope, we can’t. Rust can’t deduce type for three… I gave up.

May be someone will pick up the banner and solve the challenge.

--

--

George Shuklin
journey to rust

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.