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

void returns in switch expressions #3020

Open
water-mizuu opened this issue Apr 26, 2023 · 6 comments
Open

void returns in switch expressions #3020

water-mizuu opened this issue Apr 26, 2023 · 6 comments
Labels
request Requests to resolve a particular developer problem

Comments

@water-mizuu
Copy link

Describe the problem you are trying to solve, why is it hard to solve today?

In the latest dev build (3.1.0-40.0.dev), I've been trying to update my library to using patterns and the such, and as a preliminary, I have to say that the newest features are very much appreciated.

However, there is a certain pattern that I have noticed in code that is not accepted by the compiler, but is accepted by intellisense. Observe the following snippet.

import "dart:math";

final Random random = Random();

bool? threeState() => switch (random.nextDouble()) {
      < 0.33 => null,
      >= 0.33 && < 0.66 => false,
      >= 0.66 => true,
      _ => throw Error(),
    };

void doesNothing(void Function() function) {
  function();
}

void main() {
  doesNothing(() => switch (threeState()) {
        null => print("null"),
        true => print("true"),
        false => print("false"),
      });
}

I'd expect that this would run fine, since the void values aren't used, but the compiler complains that This expression has type 'void' and can't be used.

This begs the question, is this intended? Will this be changed?

@water-mizuu water-mizuu added the request Requests to resolve a particular developer problem label Apr 26, 2023
@eernstg
Copy link
Member

eernstg commented Apr 26, 2023

Check out this one: dart-lang/sdk#52136.

@leafpetersen
Copy link
Member

It is pretty odd that we disallow this. We don't do this elsewhere (e.g. conditional expressions are allowed to return void).

@munificent
Copy link
Member

I believe the main issue for this is #2907. I'll close this one as a duplicate.

For what it's worth, there's nothing in the patterns specification that says it's an error for a switch expression's case body to have type void. Given that, I would expect it to not be an error and was surprised that it is. I think this is an implementation bug.

(It may be that some on the language team prefer this behavior and want the spec to be changed to follow the CFE behavior. But at least as it currently stands, the implementation doesn't follow the spec and the spec is by default considered the source of truth.)

@your-diary
Copy link

your-diary commented May 11, 2023

Even if this issue was fixed, the code below wouldn't compile yet, becase switch expression at a start of an expression statement is explicitly forbidden by the spec (#3061).

enum Color { red, blue, green }

void main() {
  final color = Color.red;
  switch (color) {
        Color.red => print("red"),
        Color.blue => print("blue"),
        Color.green => print("green"),
  };
}

In Rust, the equivalent code is valid and this kind of code is quite often found in Rust codebase.

enum Color {
    Red,
    Blue,
    Green,
}

fn main() {
    let color = Color::Red;
    match (color) {
        Color::Red => println!("red"),
        Color::Blue => println!("blue"),
        Color::Green => println!("green"),
    }
}

(Of course we can use switch statement but, in small cases like this, the use of switch expression would be more terse IMHO.)

@water-mizuu
Copy link
Author

@your-diary You can use a switch expression top level by wrapping it in a parenthesis, forcing it to parse an expression, which includes the switch expression. It's not pretty, but it works.

enum Color { red, blue, green }

void main() {
  final color = Color.red;
  (switch (color) {
        Color.red => print("red"),
        Color.blue => print("blue"),
        Color.green => print("green"),
  });
}

@munificent
Copy link
Member

munificent commented May 11, 2023

(Of course we can use switch statement but, in small cases like this, the use of switch expression would be more terse IMHO.)

While a switch expression is more terse, if it's in statement position, the best practice is to write a switch statement. That sends a clearer signal to the reader that point of the switch is the side effects inside the case body, and not the value that it may or may not evaluate to.

Using ?: is more terse than if-else too, but I still wouldn't want to see code like:

main() {
  isMonday ? print('Monday') : print('Some other day');
}

Brevity is important, but clarify is important too and sometimes the shortest code isn't the clearest code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

5 participants