language
language copied to clipboard
Allow `default` in a switch expression (as an alias for `_`)
Using _ => defaultValue
is a pretty common pattern in a switch expression. But default
is more natural for, well, default values. It would be more readable if switch expressions allowed you to use default
to denote that this is the "catch-all" case.
String getName(int index) => switch(index) {
1 => "One",
2 => "Two",
3 => "Three",
default => "Some number",
// instead of
_ => "Some number",
};
I could be wrong, but I don't think this is worth doing. Using _
is quite a bit shorter than default
. Honestly, I wouldn't be surprised if _
became the idiomatic way to write default cases in switch statements too.
It's not the character length, it's the readability. I know _
is often used to symbolize "we don't care about the value" but there's a slight difference between "value we weren't going to use" and "value that didn't meet our condition". Also, if the meaning of _
is "default value", it makes sense to be able to say default => value
.
EDIT: also, if default
is used more often (as in the enhanced default parameters/arguments proposals that would enable copyWith
), this would make its usage more uniform
This is closed way too fast IMO. Folks don't even have the time to vote
I very much prefer writing default
over _
too.
Overall switch expressions are too different from switch statements to me. I would be in favour of anything that bridges the gap between the two syntaxes.
This includes default
, among other things.
I would add:
default
is a reserved keyword. If we can't even use it inside a switch when that it's only usage and should use _
instead, then let's remove default
from the list of reserved keywords.
"default" is an important english word. Not being able to name a variable default
is quite problematic
Overall switch expressions are too different from switch statements to me. I would be in favour of anything that bridges the gap between the two syntaxes.
default
is a reserved keyword. If we can't even use it inside a switch when that it's only usage and should use_
instead, then let's removedefault
from the list of reserved keywords.
We could agree on removing default
and using only _
. There were many times that I wanted to name something as default
and couldn't.
This way we would be both consistent and more flexible.
I still think default
is much more readable. And it's more intuitive to newcomers too.
default
is used in many languages, but _
is quite rare overall.
Or, use the approach Dart usually takes -- make default
a contextual keyword, which only becomes reserved in specific contexts, like switch
expressions. Quite a few Dart keywords are actually only contextual, like async
, show
, and yield
(subscripts 1 and 3 in the table).
The default
case inside a switch means 'Execute the corresponding body when none of the cases match'. And the wildcard pattern _
inside a match expression means 'Execute the corresponding body when none of the patterns specified above it match'. They have different semantics(one can and should be allowed to write default
case at top but _
always comes last). Patterns inside a match expression cannot be re-arranged as freely as cases inside a switch because the way they execute is and should be different and this is enough to make them two different constructs. Overloading the keyword switch
to mean match
expressions is the exact reason why people are getting confused and overloading default
/_
will make things even more confusing.
I agree that _
is not natural at first. I don't know the exact reason why many languages decided to use _
instead of something random to represent a wildcard pattern but it's very common. It's short, easy to type and read, and you'll get used to it fast. I've seen people going further to define unique distinct semantics for this anonymous variable(_
):
-
If users are allowed to bind anonymous variable then it gets bound during matching:
var res = switch (a) { 1 => "One", 2 => "Two", _ => "Do something with $_", // It's better than: // _ => "Do something with $a",// to write a, I've to first do a look up at switch(_) };
-
Or anonymous variable are always unbound:
// which allows this void f(_, _, _) {} // better than this void f(_, __, ___) {}
-
Having them bound at some locations and not at others, results in:
String a = '1'; var _ = '2'; var res = switch (1) { String a => a.toUpperCase(), var _ => _, }; print(res); // see if you can guess the value of 'res' given that switch('hi') gives you 'HI'
Anonymous variable(_
) carries no description of value so having it always unbound makes more sense to me.
And the wildcard pattern _ inside a match expression means 'Execute the corresponding body when none of the patterns specified above it match'.
I think your definition, "when none of the patterns specified above it match", is a bit flawed.
I interpret _
as a pattern. This pattern match anything. So, the question you should be asking when using a switch statement is, 'Does the variable x
match against the pattern y
'? Which in _
case means 'Does the variable x
match against the pattern _
, a pattern that match all possible values".
I agree that _ is not natural at first. I don't know the exact reason why many languages decided to use _ instead of something random to represent a wildcard pattern but it's very common.
Given the prior definition I read it naturally. The answer is yes it matches.
I do agree that default
and _
have different semantics thought.
I think your definition, "when none of the patterns specified above it match", is a bit flawed.
v v v v d w
a a a a o p h E
r r r r r i N
i l V
l g t m n e .
= = = = t y
' ' ' ' o
l g t m l u
o o o e + A
o o ' g r
k d + e
s ' t N
' + o
m t
S
u
r
e
I interpret
_
as a pattern... Given the prior definition I read it naturally.
I understand what you mean by that part. I can start seeing _
as having a special meaning just like I see special meaning in !
and ||
(logical or). It won't be natural at first and neither was ||
but overtime I'll get used to it and it'll become almost natural. I'm not sure if that's what you were trying to say but I can't think of any other logical explanation of you interpreting _
as a pattern.
I was also hoping to use default in switch expressions. With syntax highlighting, _
is easy to overlook, whereas keywords are typically colored differently. I also find default
to be more pleasing to look at, but I'm not sure if others share that opinion.
An exaggerated example:
final withoutDefault = switch ((2, 5, 4, 3)) {
(1, int a, 3, _) => 1,
(_, 3, _, 5, 5) => 2,
(double a, 6, _, 3) => 3,
(_, 1, _, 3) => 4,
(_, 4, _, _) => 5,
_ => 6,
};
final withDefault = switch ((2, 5, 4, 3)) {
(1, int a, 3, _) => 1,
(_, 3, _, 5, 5) => 2,
(double a, 6, _, 3) => 3,
(_, 1, _, 3) => 4,
(_, 4, _, _) => 5,
default => 6,
};
It's not a huge change -- and not something to delay other language features for, in my opinion -- but it would be nice to have.
it would be good to have default be a valid way to express the empty pattern, since when I switched to using switch expressions, I expected them to be syntactically similar to normal switch, like in Java or even kotlin.
They have different semantics(one can and should be allowed to write
default
case at top but_
always comes last).
There is no value in having a default
case appear before any other cases because it would mean those later cases are definitely never reachable and thus dead code.
The _
pattern is useful in multiple places because it can be nested inside larger patterns. Even as a standalone pattern in a case
, it can be useful outside of the last case because of guards:
switch (numbers) {
case []: print('Empty');
case [1]: print('Contains only 1');
case _ when numbers.contains(1): print('Contains 1 somewhere in it.');
case _: print('Does not contain 1.');
}
Default cases are less useful because they don't have guards. Really, the only thing default
has going for it is age and familiarity. It's more verbose, less flexible, and less expressive.
If default
is just an alias for case _
then isn't it just as (in)expressive/flexible? Also, it's 1 character longer but I wouldn't call it more verbose because it's just one word that does exactly what it says.
If
default
is just an alias forcase _
then isn't it just as (in)expressive/flexible?
It's not simply an alias for case _
, because case _
can have a guard (when
clause) but default
can't. It's less flexible than _
because default
can only appear as a standalone case, but _
can be nested in other patterns.