Generic Defaults ~ Clazz[ T = Int ]

Noticed feature, which will fit perfectly in Scala-lang ecosystem
Was surprised that it is not in spec yet

The idea was taken from Typescript
Starting with TypeScript 2.3, users can optionally add a default type to each generic type parameters. It looks like this:

`class Field<Type, Key = Type> { ... }
new Field<number> ...
new Field<number, string> ...`
4 Likes

Rust has a version of this as well. I agree it would be really nice. Although, I think curried type parameters with type inference may give us most of the win without adding more complexity.

If you had you example:

class Field[Type][Key] { ... }

Then possibly new Field[Number] would be enough to infer Key = Number in the rest of the code.

On the other hand, methods allow both default parameter and multiple parameter lists, so a symmetry for types makes sense.

More than a default value, it would be also great that if one used “named type arguments”, the unspecified type arguments would be inferred (if no default is given). I have a vague memory that this was deliberated a long time ago. Something like

def foo[A](m: Map[String, A]): Option[A]

foo(Map.empty[V = Int])  // K = String inferred
6 Likes

This would be extremely useful in instances when you have a method taking multiple complex type parameters, and you want all but one of your type arguments inferred, but end up having to write all of them explicitly anyway because of that one argument that must be given explicitly.

Do you remember what the issues or objections were? From my comfy chair where I don’t have to write the implementation, it seems like it’d be pretty straight-forward to implement.

Named type arguments were a part of Dotty for a while but removed because the SIP committee voted against it, my recollection was that people disliked having the names of type parameters suddenly become part of your API, especially since they’re usually meaningless one-letter names, but you’d have to dig up the meeting minutes/video to get the details.

1 Like

If they are meaningless names, why do we come to fisticuffs over whether it is A or T?

Looks up the word ‘fisticuffs’ - I mean, it’s obvious it should be A. Currently reading a Rust tutorial, and equally appalled by the angle brackets and the T in <T>.

TypeScript recommends meaningful names, even if we don’t have any named type parameters

Named type parameters were withdrawn because they did not meet the criteria why a feature had to come for 3.0 and not later. It was neither a restriction nor a way to compensate for one, it did not made life easier for beginners, and it was not related to foundations.

So it won’t be in 3.0. It might be reconsidered for later, but we’d have to do a new proposal and review that from scratch.

3 Likes

What about curried type parameters? If I remember correctly it was mentioned that it’s more invasive but still could make it into some 3.x release? Any idea of when that may happen?

An important thing to consider is that IIRC, defaults for type parameters prevent type inference for these parameters in TypeScript, which is a pretty big restriction, and may not fly in Scala. Or maybe it’s not so important for the use cases considered, who knows?

So I think we’d need a few good motivating examples to justify looking into this. It’s not a no-brainer thing to implement, despite what it seems.

In any case, it would surely fall into the same categorization as named type arguments, as something that can wait for after Scala 3.0.

What would happen in a case like this if we had default type parameters?
def foo[A = Int](bar: A = "baz"): A = bar

If the rule is “no type inference for type arguments with default”, then that example should be illegal.

Otherwise, one would have to clarify when the default type argument applies. You can’t make the rule simply “apply default if no type is inferred”, because usually, there is always some type inferred, even if it is Nothing or Any.

1 Like