Skip to content

Conditional statements #62

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

Open
xster opened this issue Oct 25, 2018 · 15 comments
Open

Conditional statements #62

xster opened this issue Oct 25, 2018 · 15 comments
Labels
request Requests to resolve a particular developer problem

Comments

@xster
Copy link

xster commented Oct 25, 2018

Not sure if 'conditional statements' is the right terminology but frequent issues while using Dart as UI are as follows:

Widget build(BuildContext context) {
  return CupertinoPageScaffold(
    child: ListView(
      children: [
        PageHeader(),
        isSignedIn ? SignInButton : justDon'tDoAnything
        RestOfThePage()
      ],
    ),
  );
}

In the case above, we don't actually want to return null since null has a different semantic meaning as one of the list elements.

There are of course imperfect work-arounds such as appending ..where((Widget item) => item != null) or returning : SomeFlutterWidgetThatDoesn'tDoAnythingInTheListView but they're still impedances to Dart as UI.

Another example is

WidgetA( // <= constructor
  paramA: overrideValueA,
  paramB: ifIShouldOverride ? overrideValueB : justDon'tDoAnythingAndLeaveConstructorDefaultWhichMayBeDifferentFromNull
)

Again, the present workaround solution is to wrap the whole constructor and invoke it differently twice, but it would be great if this can be expressed succinctly in the spirit of #47

@yjbanov
Copy link

yjbanov commented Oct 25, 2018

See also: https://github.com/munificent/ui-as-code/blob/master/ideas/control-flow-elements.md

@mit-mit mit-mit added the request Requests to resolve a particular developer problem label Oct 31, 2018
@mit-mit
Copy link
Member

mit-mit commented Oct 31, 2018

cc @munificent

@lrhn
Copy link
Member

lrhn commented Nov 1, 2018

I very strongly recommend to always let explicitly passing null mean the same thing as omitting an argument. Dart doesn't enforce that. I hope it eventually will (e.g., if we get non-nullable types, it might mesh well with that).

Until then, it would be possible to reuse the if syntax of control-flow-elements for arguments as well.

@yjbanov
Copy link

yjbanov commented Nov 1, 2018

passing null mean the same thing as omitting an argument.

How would that work in the presence of default values?

@Hixie
Copy link

Hixie commented Nov 1, 2018

I believe we have cases in Flutter where we have arguments where "null" is a reasonable value to pass, and where "null" is not the default. It's very hard to grep for these cases though and I don't remember any off-hand.

@xster
Copy link
Author

xster commented Nov 1, 2018

If I properly understood Ian's comment, we have 2 patterns:

  1. Things are built the way the immutable Widgets are constructed. If a default border argument defaults to a particular type of border, passing null explicitly means let it not have a border.
  2. Defaults come in later when concretely building the subtree the immutable Widget was meant to represent and we do things like InnerWidgetThatWeCompose(border: border ?? kSomeDefaultBorder).

Here, option 1 is great because an immutable UI representation actually represents the UI it's mean to represent without additional implicit runtime interpretations. But option 1 introduces the issue described in the original post.

@mdebbar
Copy link

mdebbar commented Nov 2, 2018

Despite all the problems that undefined causes in JavaScript, this is one case where it provides a nice solution.

@matanlurey
Copy link
Contributor

@lrhn:

explicitly passing null mean the same thing as omitting an argument. Dart doesn't enforce that. I hope it eventually will

So does that mean that, say, f will print 5 below twice?:

void f([int x = 5]) {
  print(x);
}
void main() {
  f(); // 5
  f(null); // 5
}

It would be really weird if null means one thing elsewhere in the language, but means omit here.

@yjbanov
Copy link

yjbanov commented Nov 2, 2018

I think the use-cases listed in this discussion, where null or undefined are proposed as solutions, seem to actually want a more direct way to express more states a variable can be in other than the range of values in the normal state. I don't know what the most idiomatic approach would be for Dart, but that's what Rust and Swift use enums for.

@mdebbar
Copy link

mdebbar commented Nov 2, 2018

@yjbanov in order for the solution to work properly with default parameter values, it needs to be builtin. We can't do that with a user-defined enum.

Also, FWIW, I just remembered a clever approach used by some JS libraries. It uses the list spread operator like this:

Widget build(BuildContext context) {
  return CupertinoPageScaffold(
    child: ListView(
      children: [
        PageHeader(),
        ...(isSignedIn ? [SignInButton] : [])
        RestOfThePage()
      ],
    ),
  );
}

It works, and I think it's better than extracting the children list into a variable, but is still not ideal.

@rakudrama
Copy link
Member

Does the control-flow collections feature address this issue?
The original example can now be written as:

Widget build(BuildContext context) {
  return CupertinoPageScaffold(
    child: ListView(
      children: [
        PageHeader(),
        if (isSignedIn)
          SignInButton,
        RestOfThePage()
      ],
    ),
  );
}

@lrhn
Copy link
Member

lrhn commented Jan 10, 2022

I believe an if-element solves the first problem, but not the second (conditionally passing a named parameter).

@Levi-Lesches
Copy link

For consistency, some have proposed adapting the same syntax to parameters:

WidgetA(
  paramA: valueA,
  paramB: if (shouldOverrideB) overrideValueB,
  // Otherwise, just omit the parameter entirely instead of passing null
)

See also: #1039, #219,

@lrhn
Copy link
Member

lrhn commented Jan 11, 2022

I hope we'll eventually get something like an if-argument too, but until then, the original problem of this issue isn't solved.

@munificent
Copy link
Member

the original problem of this issue isn't solved.

Puts on pedantic hat...

The original issue has two examples. Collection-if does fix the first one, because it's inside a list literal argument. We don't have a solution for the second one yet.

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

10 participants