-
Notifications
You must be signed in to change notification settings - Fork 205
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
Proposal: operator !! (opposite of ??) #361
Comments
With this definition, The operation, by itself, seems reasonable. If you could write the |
Great catch Lasse... |
As per #706 I would like to suggest a slight change: instead of |
As another data point, this has been a substantial source of pain in Dart Sass's null-safe refactor (I count about 40 instances of extension NullableExtension<T> on T? {
V? andThen<V>(V Function(T value) fn) {
var self = this; // dart-lang/language#1520
return self == null ? null : fn(self);
}
} but it's awkward, particularly due to the lack of constructor tear-offs.
#1201 provides a neat solution to this in |
+1 to this proposal-regardless of the specific characters used to implement the operator. I'm coming from Scala world where Options are king and the following is an extremely common paradigm:
This comes up commonly with default parameters in Dart:
This is already supported if we're trying to call a class method. Notice how much readability improves when such an operator is supported:
Adding a "compute iff not null" operator would be highly useful and make writing functional-style code in Dart much friendlier. |
That extension OptionMap<T> on T? {
R? map<R>(R? Function(T) convert) => this == null ? null : convert(this);
} I'd have made it an operator if we could have generic operators. |
Is dart supports operator type args? |
No, operators cannot be generic methods in Dart. |
I have to say, I've seen a few issues with exactly this proposal -- and it would massively help with Flutter code. child: data == null ? null : MyLongWidgetName(
data: data,
more: properties,
)
// vs
child: data !! MyWidget(data: data, more: properties) (keep in mind, this is usually a few indents deep) @lrhn, do you think this can be considered to be added to Dart? |
This syntax (or something equivalent) has been proposed a few times before. My main worry is that it only works for variables which can be promoted, and it relies on promotion. Not an impossible feature, can definitely be useful, and if we combine it with inline variable declaration, it might also avoid reading the value twice and work with non-variables; child: (var x = something.data) !! MyLongWidgetName(data: x, more: properties); (That's with a the proposal to bind-and-promote in local variable declarations, like #1420). Another issue is that by making the Another option would be a nullable conditional expression with no else branch (the else branch is always null), data != null ?: something(data) But, honestly, I don't think an implicit data != null ? something(data) : null which is being explicit about what happens, and likely easier to read. Introducing an implicit |
I agree, and that's where I went with it at first. But let's do this in the context of Flutter, since that's where it's most useful: child: data != null ? Center(
child: MyWidget(dataObject: data)
) : null Well, I decided I didn't like that hanging child: data == null ? null : Center(
child: MyWidget(dataObject: data)
) Now, with a slightly longer name and a few more indents: class MyCard {
List<Widget> children;
@override
Widget build(BuildContext context) => Card(
child: ListTile(
subtitle: children == null ? null : Column(
crossAxisAlignment: CrossAxisAlignment.start
children: children,
)
)
);
} class MyCard {
List<Widget> children;
@override
Widget build(BuildContext context) => Card(
child: ListTile(
subtitle: children !! Column(
crossAxisAlignment: CrossAxisAlignment.start
children: children,
)
)
);
} With much indentation and long widget names, the extra Re: duplication, I would be in support of a syntax like: class MyCard {
List<Widget> children;
@override
Widget build(BuildContext context) => Card(
child: ListTile(
subtitle: (var children) !! Column(
crossAxisAlignment: CrossAxisAlignment.start
children: children,
)
)
);
} |
I realized this might just be well served just with an extension. extension Optional<T extends Object> on T {
V apply<V>(V Function(T) func) {
return func(this);
}
} Highly contrived pure Dart and Flutter examples: Foo? getValue() {...}
ProcessedFoo? processedValue = getValue()?.apply((v) => processFoo(v));
// or, slightly simplified:
processedValue = getValue()?.apply(processFoo); class MyWidget extends StatelessWidget {
const MyWidget(this.child);
final Widget? child;
@override
Widget build(BuildContext context) {
return Container(
child: child?.apply(
(c) => Padding(
padding: const EdgeInsets.all(4),
child: c,
),
),
);
}
} It's a tad verbose but its more explicit than |
The The Patterns offer ways to test for switch(e){var v? => processFoo(v), _ => null) (A nullable switch expression, which doesn't require being exhaustive, so has an implicit |
I love this proposal, but I believe a better syntax for this would be Then, your example could be updated to this instead @Levi-Lesches class MyCard {
List<Widget> children;
@override
Widget build(BuildContext context) => Card(
child: ListTile(
subtitle: children ?| Column(
crossAxisAlignment: CrossAxisAlignment.start
children: children,
)
)
);
} Additionally, it would be great if a tear-off could also be used Original return maybeData == null ? null : utf8.decode(maybeData) After // Normal use with new `null or` operator
return maybeData ?| utf8.decode(maybeData);
// Sugar syntax
return maybeData ?| utf8.decode;
|
I really like the before mentioned proposal of @SupposedlySam, especially this tear-off idea. I think we should either use By the way, one can use the following dart function meanwhile: Y? $<X, Y>(X? x, Y? Function(X v) y) => x == null ? null : y(x); It can lead to a smaller expression, depending on the length of the original |
Meanwhile, I created a dart extension called Usagefinal int? a = null;
final int b = 1;
print(a.nmap((n) => n + 1)); // null
print(b.nmap((n) => n + 1)); // 2 |
Small feedback/PSA for other readers: Why? This changes the usage to |
@caseycrogers interesting... I am not sure though how one would write it differently than I did on the Edit: never mind, I misunderstood your initial comment, you would indeed change the usage to |
Proposed solution to #360.
Where
a ?? b
is sugar fora != null ? a : b
, there may be value in adding!!
defined asa == null ? null : b
.Example: calling a function when the parameter is not null.
Example: awaiting a future when its not null
Example: asserting an object is fully initialized
Similar to #219 except I think it has a few different advantages:
Disadvantages:
!
and not throwing an exception on null is confusing. Maybe?!
or!?
?The text was updated successfully, but these errors were encountered: