A recent comment on the “partial turbofish” RFC by @nikomatsakis started a discussion on named type parameters of types and traits and how the current situation does not scale. An excerpt:
I have been historically quite grumpy with how our defaults in type parameters in any case. In particular, I don’t like them being a linear list. I want to give names. Consider HashMap:
pub struct HashMap<K, V, S = RandomState>
What happens if we want to add an allocator parameter (say) to HashMap? Now, in order to specify the
allocator, I have to specify the S parameter too? That seems dumb. This now seems sort of connected to
optional parameters in functions, of course.
This gave me an idea for a solution:
pub struct HashMap<K, V, S = RandomState, A = Heap> { .. }
let foo: HashMap<K, V, {A} = OtherAlloc> = HashMap::default();
// variations with different sigils:
let foo: HashMap<K, V, [A] = OtherAlloc> = HashMap::default();
let foo: HashMap<K, V, |A| = OtherAlloc> = HashMap::default();
let foo: HashMap<K, V, #A = OtherAlloc> = HashMap::default();
Here, {A} refers to name A as used in HashMap<K, ..> and I think it looks pretty good.
If we can infer K, V then we can also write:
let foo: HashMap<{A} = OtherAlloc> = HashMap::default();
// ..
To which, in response, @comex proposed:
HashMap<K, V, A: OtherAlloc>
but said that:
Might be easy to confuse with trait bounds, but that’s not so different from the similarity between a struct declaration, struct Foo { a: T } and the syntax for a value, Foo { a: val }.
I’m extracting out that discussion now and hoping that we can find a good solution together on this forum so that we can start an RFC about it eventually.