Recursion
To implement some feature, we may want to use recursion over the arity of the tuple. For instance, let's implement a trait that gives the arity of a tuple as a const value:
trait Arity { const VALUE: usize; } impl<Head, (..#Tail)> Arity for (Head, ..#Tail) { default const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; } impl Arity for () { const VALUE: usize = 0; }
I guess this example won't be work for Rust because Rust want to check generics before monomorphization.
While checking validity of <(..#Tail) as Arity>::VALUE + 1
, there is no witness of (..#Tail)
being Arity
. Instead we could use specialization to ensure all variadic tuple type have instance of Arity
:
impl<(..#Ts)> Arity for (..#Ts) {
default const VALUE: usize = 0;
}
impl<Head, (..#Tail)> Arity for (Head, ..#Tail) {
const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1;
}
Similarly, the variadic tuple expansion can't be just an "expression template" and there must be a static semantics to be given. For example,
fn test<(..#Ts)>((..#t): (..#Ts)) {
let s = String::new();
(..#{ drop(s); t });
}
Defining test
should be error because test<(i32, i32)>((0, 0)) expands to a double drop.
However, expanded test<(i32)>((0,)) is valid and thus it is an approximate semantics in the sense.