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

Allow control statements to be an expression #1211

Closed
danielgomezrico opened this issue Sep 9, 2020 · 2 comments
Closed

Allow control statements to be an expression #1211

danielgomezrico opened this issue Sep 9, 2020 · 2 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@danielgomezrico
Copy link

danielgomezrico commented Sep 9, 2020

Currently the result of control statements like if or try/catch can not be assigned into a variable.

I know that there are some operators that helps with simple cases like ? but when each of the cases is bigger then the line code tends to be bigger than one or two lines and it can become a mess.

  • Helps the developer to express the intention of the controls easily.
  • It allows you to declare the button variable in the example as final in the declaration, helping again expressing the intention of the code.

Current 1

Lets say we have a build function that builds a widget with some parameters in one case and with others in other case:

// Cant be final even if we already know that it will be assigned only once
Widget button;

if (page == Page.map) {
  button = build(
    Icons.list,
    "List",
    () => setState(() => page = Page.list),
  );
} else {
  button = build(
    Icons.map,
    "Map",
    () => setState(() => page = Page.map),
  );
}

Current 2

It can be used in simple cases but the indentation becomes tricky and does not support more than 2 different cases.

 Widget button = page == Page.map
        ? build(
            Icons.list,
            "List",
            () => setState(() => page = Page.list),
          )
        : build(
            Icons.map,
            "Map",
            () => setState(() => page = Page.map),
          );

Desired

As you can see it assigns the result into the variable declaration.

final button = if (page == Page.map) {
  build(
    Icons.list,
    "List",
    () => setState(() => page = Page.list),
  );
} else {
  build(
    Icons.map,
    "Map",
    () => setState(() => page = Page.map),
  );
}

Some references

@danielgomezrico danielgomezrico added the feature Proposed language feature that solves one or more problems label Sep 9, 2020
@lrhn
Copy link
Member

lrhn commented Sep 11, 2020

See also #352, #132 and some of #307 and #27.

The challenge with making control statements be expressions is that expressions must have a value, but statement don't inherently have one.

The solution here seems to be using the value of the expression of last expression statement of the statement.
The examples here are not very convincing since it's only if where each branch is a single expression statement, so you could do the same thing using conditional expression - which can be chained into more than two branches:

var x = test1
  ? expression1
  : test2
  ? expression2
  : test3
  ? expression3
  : expression4;

A more interesting example would be something using a loop statement or a switch.

var x = switch (kind) {
  case Enum.number: 4; break;
  case Enum.string: "string"; break;
  case Enum.bool: true; break;
}

or

var x = while (y > 0) { x += y--; x; }

We have had other requests for "expression-switch", which would make sense. The rules for an expression switch would be that the case-blocks would be expressions, not statements, and the switch must be exhaustive (or we default to default: null). The same way the "expression if" (?/:) must have an else branch, to ensure that the expression has a value.

For a do-while loop, we could ensure that the body has a value, but a for or while loop might not run the body at all, so it would have to have a default value of null (unless we introduce loop-else-branches, #171).

Changing e1 ? e2 : e3 to use if (e1) e2 else e3 (an if-expression where the branches are expressions) in general would remove one very annoying use of ? and : in our grammar, and avoid a lot of the ambiguities we've suffered with ? on types and : in map/set literals. It would probably be a net improvement.

@danielgomezrico
Copy link
Author

Thanks for the explanation 👍 , since this is already requested I will close it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

2 participants