# What is the use case for multi-type-parameter generics?

In C#, one can define a class/method/function with multiple type parameters. For example,

// function
void foo<T1, T2>(T1 x, T2 y) { /*body*/}

// class
class Bar<T1, T2> { /*body*/ }


I understand how to use it, but I don't understand why I need it. So I'm hoping someone can answer the following questions:

1) What is the use case for multiple type parameters?

2) Based on the use case given in Question 1, what are the alternative solutions for that use case if multiple type parameters is not a feature of the language in use?

• Cross-posted: cs.stackexchange.com/q/95280/755, stackoverflow.com/q/51348045/781723. Please do not post the same question on multiple sites. Each community should have an honest shot at answering without anybody's time being wasted. – D.W. Jul 15 '18 at 17:07
• "but I don't understand why I need it." You don't need high-level programming language at all, you can do anything on asm. But somewhy you prefer not to program on asm when you can do it on C#. – rus9384 Jul 15 '18 at 17:15
• @D.W. It depends on the context of the case. If the same question could and should be answered from different perspectives on different sites, it's nothing wrong to post it on both. Another question is whether it should be answered from different perspectives. Computer scientist vs. programmer. – rus9384 Jul 15 '18 at 17:17
• @rus9384, I appreciate your reasoning, but that's not what our community policy says. – D.W. Jul 15 '18 at 17:23
• @D.W. I believe the example was pretty bad. More robust one would be to ask the same question on philosophy and buddhism. – rus9384 Jul 15 '18 at 17:27

Some use cases for multiple type arguments include

• maps/dictionaries Map<K,V>, where you have one key parameter and one value parameter
• product types Pair<A,B>
• sum types, AKA variants Variant<A,B>, which represent a value which might be either of type A or of type B
• Function-like types Func<A,B> representing a function from A to B
• "Visitor" objects for parametric types. I.e. a visitor for List<A> is ListVisitor<A,R> where R is the return type of the visitor.

If we did not have multiple type arguments, or any other way to emulate multiple argument types (e.g. nested parametric classes class T<A> { class U<B> { ... which are a sort-of curried version of the two-arguments class), we could not express the examples above in a generic way.

Of course, a programming language could disallow generic classes and still have a specific primitive type for some of the examples above. For instance, Func<A,B> could be a primitive type, instead of a user/library-defined class type.

• Multiple types are also redundant if product types are primitive types (e.g. (Int, String)) and the language offers projection operators on these pairs: class Map<T> { /* use first(T) and second(T) as types here */ }. Then one only needs to write Map<(Int, String)>. – ComFreek Jul 15 '18 at 16:03
• @ComFreek You can't define Map that way. Map is a constructor of kind * -> * -> *. You're approach would make it * -> *, which couldn't enforce the type parameter to be a pair. That's exactly why we have kinds. – gardenhead Jul 15 '18 at 19:28
• @gardenhead Just create a compiler error when T is not a pair... (at least C++ allows that) – user91718 Jul 16 '18 at 1:28
• @gardenhead: I think you're assuming too much about other properties of the language. There's no reason that the language couldn't let Map impose constraints on its type parameter, analogous to Haskell typeclasses, C# where constraints, Java extends bounds, etc. – ruakh Jul 16 '18 at 1:54
• @ruakh That's precisely what kinds are for... imposing constraints on a type constructor. – gardenhead Jul 16 '18 at 2:00