Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need something alternative to switch #307

Closed
Afsar-Pasha opened this issue Apr 10, 2019 · 11 comments
Closed

Need something alternative to switch #307

Afsar-Pasha opened this issue Apr 10, 2019 · 11 comments

Comments

@Afsar-Pasha
Copy link

Afsar-Pasha commented Apr 10, 2019

I have seen the #27, but I think we don't need to implement the same feature with the same syntax.
Since the switch statement in dart looks old, so maybe a new expression(returns value) can be made to dart which could be used instead of the switch statement.
Following are few syntaxes I like,

1

var result = switch (x) {
    (a) -> 'x == a';             // No case keyword and 'a' is not constant
    (a, b) -> 'x == b or x == b';      // maybe we can use => instead of -> to avoid new keyword
    (is int, is String) -> 'x is int or String';   // No break, no fall through
    (c) -> print('x == c'); // This is not the expression value
        'x == c';       // Expression value if x==c
    -> 'Default';           // null if not specified
}

2

var result = switch (x) {
    (< a) -> 'x < a';
    (> a, < b) -> 'x > a or x < b';
    (> b && < c) -> 'x > b and x < c';
    (a) -> 'x == a';        // if no operator is specified
    (!a) -> 'x == !a';      // (!=a) for 'x != a'
}

3

var result = switch {
    (x < a) -> 'x < a';  // Just replacement for (condition1) ? '1' : (condition2) ? '2' : null
    (x > a || y > b) -> 'x > a or y > b';  //  || instead of ',' since the value instead () is an boolean expression
}

4

var result = switch x {
    a -> print('x == a');
        'x == a',     // ',' instead of ; to indicate the last statement of case a, seen this in rust
    a, b -> 'x == a or x == b', // Here anything between ',' and -> would be the case,  ignoring ',' between them
    -> 'Default',          // default if nothing is between ',' and ->
}

5 -> (2 and 4)

var result = switch x {
    a -> print('x==a');
        'x == a',
    < a -> 'x < a',
    > a, < b -> 'x > a or x < b',
    > b && < c -> 'x > b and x < c',
}

6 -> (5 and 3)

var result = switch {   // The expression type should be same-type or sub-type of both a and String
    x == a -> a.z = 6;
         a,
    x < a -> 'x < a',
    x > a || y < b -> 'x > a or y < b',
    x > b && y < c -> 'x > b and y < c',
}

Any of this syntax may be combined or altered but what I need is something that returns value based on conditions(not ?:).
I mostly like 5th and 6th approach, and would be happy if both of them or something much better or more logical is implemented.

@Afsar-Pasha Afsar-Pasha changed the title https://github.com/dart-lang/language/issues/new Need something alternative to switch Apr 10, 2019
@lrhn
Copy link
Member

lrhn commented Apr 29, 2019

This is an expression-level chained if block, plus an implicit receiver for comparisons, plus statement expressions (execute statements, then evaluate to a value).

We could make switch an expression level feature too, where the case bodies must then be expressions (and with NNBD you must have a default case if the context type is not nullable). Then we could probably also make it an "elements" feature to use in collections too.

We would have to allow non-constant switch expressions (which is not a problem, it just turns the switch into a guaranteed iterative operation, not a jump-table). However, we don't have a good way to refer to the switched value itself. Maybe we can introduce a variable for that (it?). Still feels clumsy.

As pointed out, number 3 alone can be written using ?/: today.

I'm not particularly fond of number 2. It introduces a completely new syntax, a new sub-language, that we have to parse and handle. It is not particularly general (can you only do comparisons using ==, !=, <, <=, > and >=, or can you do * 2 == 4 or | "not" (where the latter might actually be defined as returning a boolean). I'd rather introduce a variable for the switch statement (say it), so you write

var result = switch (x) {
  case it == a: ...
  case it < a ||  ...
  ...
}

so we can use our existing expression grammar.

Even then, it feels a little clumsy.
Maybe just say that if you omit the switched-on value, it defaults to true:

// version 6
var result = switch  { 
   case x == a: a
   case x < a : "x < a"
   case x > a || y < b: "x > a or y < b"
   case x > b && y < c : "x > b and y < c"
 }

I want a keyword in front of the test for parsing reasons, and using case is already supported. By saying that the default switched-on value is true, and allowing non-constant conditions, we effectively allow this case expression to check for the first true condition in a series of conditions.

This still does not allow statements in expression context, the a.z = 6; a "expression". I'm not sure that's something we want to support (let's not allow a return in the middle of an expression. If it's only an assignment expression, you can just define:

T seq<T>(void ignore, T value) => value;

and use case x == a: seq(a.z = 6, a). Not as pretty, but also doesn't require a new language feature.

@Afsar-Pasha
Copy link
Author

@lrhn

doesn't require a new language feature.

What I want is a new feature to the language.

@lrhn
Copy link
Member

lrhn commented Mar 1, 2021

It's true that break expr; is ambiguous. If only we had made labels use the same textual scope as variables, then it wouldn't be possible to have both a label and a valid expression represented by the same identifier. (Changing that might be breaking, not sure by how much, though, and if we make the style guide say that labels should be snake_case when multiword, then we dodge the issue even more).

Alternative versions of the with syntax:

break = expression; break label = expression;
break: expression; break label: expression;
break(expression); break label(expression);  // mandatory parentheses, so probably a bad idea.
^expression; ^label: expression;  // (Prefix ^ isn't used yet. Might want to reserve it for non-local returns).

@Levi-Lesches
Copy link

var result = switch  { 
   case x == a: a
   case x < a : "x < a"
   case x > a || y < b: "x > a or y < b"
   case x > b && y < c : "x > b and y < c"
 }

I really like @lrhn's version -- it's essentially a more readable x ? y : z that's been expanded for more than two conditions. It's also readable and doesn't introduce much new syntax, besides the obvious switch-as-an-expression. But I think the semantics are clear enough -- I almost always use switch to return a value anyway.

This also means we can use them in short functions:

enum ErrorType {okay, warning, critical}
Color getColor(ErrorType type) => switch (type) {
  case ErrorType.okay: Colors.green
  case ErrorType.warning: Colors.yellow
  case ErrorType.critical: Colors.red
};

Although maybe we should use a , after each expression? That way newlines won't matter, and it visually matches even closer with maps, which was always the go-to comparison in my head.

@munificent
Copy link
Member

Just trying some threads together. My latest proposal for pattern matching does include a switch expression, which would address this.

@Nikitae57
Copy link

Guys, even java already has this

@vishalpatel1327
Copy link

vishalpatel1327 commented Jul 5, 2022

If any user coming from Java then it's okay.
but if Anyone coming from kotlin then it's a headache for it let me show one example.

because kotlin is very human-readable, simple

image

but if its in Flutter Dart then you can see it.

image

@munificent
Copy link
Member

The braces inside each case in your example are unnecessary, which would make the Dart example much nicer looking.

You may also be interested in the in-progress proposal to add support for switch expressions.

@munificent
Copy link
Member

Closing this because switch expressions are now enabled in the bleeding edge Dart SDK. 🎉

@amrgetment
Copy link

@munificent I wonder is dart will or has support for when like freezed library

enum Answer{ yes,no}

Answer answer=Answer.yes;

answer.when(yes:()=>..,no:()=>)

@mateusfccp
Copy link
Contributor

mateusfccp commented Nov 21, 2023

@munificent I wonder is dart will or has support for when like freezed library

enum Answer{ yes,no}

Answer answer=Answer.yes;

answer.when(yes:()=>..,no:()=>)

The new switch expressions are already like freezed when. Not only that, freezed itself does not recommends using when anymore,1 and recommends using switch instead. They are probably going to deprecated when eventually.2

Your code could be rewritten as:

enum Answer {yes, no}

Answer getAnswer() => Answer.yes;

void main() {
  final answer = getAnswer();
  final result = switch (answer) {
    Answer.yes => ...,
    Answer.no => ...,
  };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants