One character generics

What's the motivation for preferring one character generic parameters? IMHO it makes code harder to read. Compare:
impl<K, V, S> HashMap<K, V, S> where K: Eq + Hash, S: BuildHasher

impl<Key, Value, HashBuilder> HashMap<Key, Value, HashBuilder> where Key: Eq + Hash, HashBuilder: BuildHasher

In my main language right now (Swift) I really like descriptive generic parameters. Do people really prefer one character names and why?

Thanks for your opinion.


I try to use descriptive names for generics while still keeping it clear that they're not concrete types:

impl<TKey, TValue, TState> HashMap<TKey, TValue, TState> where TKey: Eq + Hash, TState: BuildHasher

I prefer that convention over either K, V, S or Key, Value, State because in the former who knows what S is supposed to be, and in the latter how do you know Value is generic and not something like serde_json::Value?


Sometimes though there really isn't much more you can say about a generic than T, like in the case of Box<T>.


I think it probably comes from C++ where quite often template parameters will be a single letter.

Also, typical generic functions/types tend to have only one or two generics and from the context it's quite obvious what the letter stands for (e.g. K means "key", P is often used with AsRef<Path>, T just means any type you want). I guess it's just because it's quicker to type, consumes less screen space and we're lazy.

You could ask the same question about lifetimes. Why do we almost always use 'a instead of something more useful like 'input_string in something like struct Foo<'a> { name: &'a str }?


I think something can be figured out even for Box, e.g. Box<ValueOnHeap>.

I personally prefer using longer names and try to use them whenever feasible (RGB<Component> rather than RGB<T>). For lifetimes too, to explain why the lifetime exists ('file_content).

Sometimes it's not feasible, e.g. in complicated where clauses lifetimes and parameters are repeated so much, that it gets too verbose quickly.

Another obstacle is that there's no syntactic difference between a type, trait and type parameter. 1-letter parameters at least look different. Ideally it'd be solved with syntax highlighting, but AFAIK it can't be done in simple regex-based highlighters as used by most lightweight editors.


To me the single character is usually easier to distinguish.
It does not get confused with structs or traits.
The scope is limited. (impl is a bit larger that just on fn or struct but still confined.)
I'm quite happy using/reading single letters for common local variables, then more verbose as the scope expands.


There's established conventions for:

  • T, U for being an arbitrary types
  • K and V being Key and Value

S is a bit more unusual, but simply from the S: BuildHasher constraint it's easy to tell that it's related to the hashing.

For me the main reasons for sticking with single-letters are:

  • Easy to distinguish between type parameters and concrete types (as others have noted).
  • Less typing, especially when you have to repeat the same type many times with all its constraints.
  • Shorter type expressions ⇒ easier to parse complicated types.

I actually find it easier to read when it's short. Sure there's a small "ramp up" time where you have to familiarize yourself with the symbolic convention, but after that it becomes easier because the symbols are short and therefore easy to parse mentally, especially in longer and more complicated type expressions.

The most important thing though, is being consistent with the convention.


I'd suggest using long names in libraries. These names leak into error messages such as "cannot infer type for T". Such an error could be an annoying dead-end. OTOH "cannot infer type for WidgetContainer" might help trace the problem.


What about super-generic types like Vec<T> where you have absolutely no constraints on the type? In that case it really doesn't make sense to try and call T something like TypeContainedInVector, making the name longer isn't the same as making it more descriptive or useful. Instead you end up diluting the name with superfluous extra cruft.

As a side note, there's a really good talk on YouTube by Kevlin Henney about giving things a good name and agglutination in programming. I'd recommend looking it up if you've ever had to work in "enterprise" codebases.


From my POV, the one character parameters seem to be clarified by the Trait Bounds (much like how function arguments are often really explained by their types).

Long names and trait-bounds would probably be overkill.

1 Like

( to my mind, K etc are usually enough especially clarified by the trait bounds.. 'K:Eq+Hash' .. it might even be more productive to write a combined bound Key=Eq+Hash .. usually how things are used is made much clearer by the types)

impl<K:Key, V, B:BuildHasher> HashMap<K, V, B> {...}

(elsewhere, trait Key : Eq+Hash {} impl<T:Eq+Hash> Key for T{} )

There's some interesting proposals for C++ (maybe even incoming with concepts) where you might actually be able to use the trait names as types, as a shortcut for 'spawning' their own typeparameters automatically, although that relies on 'context sensitive grammar' which I wouldn't advocate here.

This has bothered me quite a bit about Rust conventions for a while. I do stick to it to be honest, because breaking convention can be more confusing sometimes. However, at least for those cases where it is not totally abstract, I feel it does make sense to find a more descriptive name.

There is more of this in the language though, like &str, Vec, fn, 'a… while you get used to it fairly quickly, it does make the language a little bit more enigmatic to newbies than it needs to be imho.

Not sure whether this is something that needs to be fixed, but renaming generic parameters is not even a breaking change, so it might be worth looking into for a crate.

Rust's terseness takes a bit of getting used to if you're coming from languages where that's uncommon. However, and this is subjective, I think it optimizes for the right thing - once you're comfortable (i.e. out of the newbie stage), it's nice to not have to write an essay to express common things over and over.

As for single letter generic type params, that seems to be pretty common in other languages as well. As others have mentioned, it makes it clearer that it's a type parameter and not a concrete type. It cuts down on noise once the parameters are mentally absorbed. I think it's just a matter of getting used to if coming from a background that doesn't have these conventions.

Personally, I found pervasive use of type inference more disorienting when just starting out with Rust.


For most functions, it's totally fine, because the mental overload is limited.

But once things get somewhat more complex, I am quite often lost and have to look up what a type parameter means in the definition. I'm talking about swapping back and forth between different contexts, that each have more than five generic parameters that partially overlap in meaning. This is where I wish things would have been written out.

I realize there would probably often be redundance between parameter name and trait bound. Nonetheless, I think that's fine, if it makes code easier to read. Usually code is read more often than it is written. So it makes sense to optimize for reading code, not for writing code.

1 Like

Truth be told, I'd be fine with Value here, and let my editor show me what it is through syntax coloring. Because realistically, who even reads code without syntax coloring anymore?

I'm also fine with V, for all reasons listed above, especially when they appear on the left side of a trait bound (e.g V: Hash + Eq).

But somehow TValue or ValueT strike me as redundant.