dart-lang / site-www

Source for Dart website
https://dart.dev
Other
935 stars 675 forks source link

Add recommendation to Wildcards on 'Pattern types' page #5926

Open eernstg opened 1 week ago

eernstg commented 1 week ago

Page URL

https://dart.dev/language/pattern-types/

Page source

https://github.com/dart-lang/site-www/tree/main/src/content/language/pattern-types.md

Describe the problem

In the section 'Wildcards' near the end of the page, it is mentioned that a variable pattern like int _ is a useful construct when we wish to test the type of the scrutinee (the actual example is a bit more involved, case (int _, String _):, but that's just the same thing done twice as part of a record pattern matching).

This is indeed true, but it would probably be helpful if this rather implicit recommendation is accompanied by another recommendation: It is in a sense safer to have a habit of using an object pattern (like int() respectively case (int(), String()):).

They only differ when the given type is generic, but the object pattern is more concise and convenient, and in a sense safer with generic types, and there is no reason to prefer the variable pattern with non-generic types (so we might just as well recommend that developers use the object pattern as a habit).

Here's how they differ:

Consider an object pattern whose target type is generic and whose actual type arguments have been omitted. This pattern will receive actual type arguments based on the matched value type. This means that case MyType(): will implicitly be inferred to mean case MyType<Some, TypeArguments>(): where said type arguments are chosen to be as specific as possible for the given matched value type (for instance, if we're switching on an expression of type Iterable<int> and matching case List(): then it is inferred to mean case List<int>():).

In contrast, consider the same situation except that we are using a variable pattern, case MyType _:. In this case, MyType uses instantiation to bound to obtain the omitted type arguments. If there are no declared bounds then this means case MyType<dynamic, dynamic> _: (similarly, with a matched value type of Iterable<int>, case List _: means case List<dynamic> _:).

This topic is discussed a bit more in this comment.

Expected fix

The section 'Wildcards' could have a concise description of this topic and a reference to the section 'Object' that occurs a few lines earlier. Perhaps something like this:

Consider using an object pattern (MyType()) to test a type rather than a variable pattern (MyType _), especially when the given type is generic. For more details please see the section 'Object'.

The section 'Object' could then present the above line of thinking and recommend using case MyType(): rather than case MyType _: as a habit.

Additional context

No response

I would like to fix this problem.