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 nameA
as used inHashMap<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.