-
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: null-elimination operator - prefix "?" #219
Comments
I assume map literals can work on both key and value, It is annoying that positional parameters can't be handled better, but probably unavoidable as long as we don't have rest parameters (those would be similar-typed sequences that are combined in a single list, so you can omit values like in a list). Another potential use-case: |
Still sorta on the fence when it comes to the syntax. Maybe an |
Maybe the syntax to express this is already there: I'm thinking of a > 3 ? a : _ // only a if it's greater than 3
a ?? _ // only a if it's not null I'm not aware of other languages that do this, so take that with a grain of salt. Also note that |
@tatumizer My issue with the syntax is that it feels a question mark feels odd in a prefix position. I'd like it more if the question mark was against an another operator (e.g. a suffix to |
In my eyes |
Yes, that's exactly my concern. The concept of "Nothing" is already hidden in plain sight: With that said, "Nothing" is no data type. It's purely syntactical sugar, as you wrote. As such, it shouldn't be confused with the Optional type, or used in situations where the latter makes more sense. |
Sure, but that's an argument for Being able to conditionally ignore expressions would be a pure convenience feature, to make your code shorter. That's tempting in cases where it's super obvious what's happening, but I'm concerned that things like In my opinion, many of the (valid) pain points could better be remedied with Optionals. And sometimes, a good ol' |
It's a common theme that some expression should only be evaluated to completion if some sub-expression is non-null. The Imagine an expression of the form It's nigh unreadable, though. :) |
Forgive me for over-interpreting the proposals here, in order to emphasize a particular danger that seems to be relevant. I can see proposals where the prefix For that, I'm a little bit worried about having a large construct and then making that construct mean something very different (namely var mySet = {
canvas.drawParagraph(
(ui.ParagraphBuilder(
ui.ParagraphStyle(textDirection: ui.TextDirection.ltr),
)..addText('Hello, world.'))
.build()
..layout(ui.ParagraphConstraints(width: logicalSize.width)),
ui.Offset(...)),
ui.window.render((ui.SceneBuilder()
..pushClipRect(physicalBounds)
..addPicture(ui.Offset.zero, ?picture)
..pop())
.build()),
} So do we want that whole thing to happen if and only if that So when we're considering this ability to "call it off", I think it's important to consistently force that property up to the front: var mySet = let ?v = picture in {
canvas.drawParagraph(
(ui.ParagraphBuilder(
ui.ParagraphStyle(textDirection: ui.TextDirection.ltr),
)..addText('Hello, world.'))
.build()
..layout(ui.ParagraphConstraints(width: logicalSize.width)),
ui.Offset(...)),
ui.window.render((ui.SceneBuilder()
..pushClipRect(physicalBounds)
..addPicture(ui.Offset.zero, v)
..pop())
.build()),
} The idea is that we can mark the whole construct as "call-offable" by using It might still be valuable enough to consider special cases like "omit this named argument", but for the more general case where we want to call it off I think it's important to make sure that nothing is called off by a tiny detail in the middle of a big construct. |
Sorry about over-interpreting! That was exactly the kind of semantics that we've had proposals for on earlier occasions. |
If we consider only the collection element case, and only the "element computation is null" case, then it might work. Say we use "suffix var x = [1, 2, computation() ??, 4]; That could work. The problem is that it only works for single elements, not for map entries. We cannot do It's not a good orthogonal feature, but it mirrors the nullability of |
Ah, the "suffix |
This comment has been minimized.
This comment has been minimized.
I personally vote for |
This would be useful for late final variables if you sometimes don't need to inizialize them right in the constructor initializer. class Something {
late final String _text;
class({String? text})
: _text = ?text; // if text is null, _text won't get assigned anything and can still be assigned later
} |
I see this has been closed as "completed". Was this implemented? Can someone please link a reference to how we can achieve this? |
It has not been implemented. The issue was closed by the original poster, not by the language or implementation teams. It's an idea that we are aware of, but haven't found any optimal syntax for yet. The general idea is a way to make a large expression evaluate to null eagerly if a subexpression evaluates to null. So, the idea is not forgotten, even if this particular feature proposal is closed. |
This proposal is based on ideas from several commentators from this thread. (In other words, I don't pretend these ideas are mine) :-)
Proposal: implement null-elimination operator ?expr to drop value of null, in contexts where such operation makes sense.
Examples:
foo({int x=0})
. Then the callfoo(x: ?expr)
is equivalent to callingfoo()
if expr evaluates to null, and to foo(x: expr) otherwisefoo([int x=0])
- then the callfoo(?expr)
is equivalent tofoo()
if expr evaluates to null, and tofoo(expr)
otherwise (only valid for the last such parameter. I'm not sure this makes sense though - to be discussed).{ "key": ?expr }
is {} if expr evaluates to null, and{"key": expr}
otherwiseAdvantages:
[ 1, 2, ?(a?.b?.c) ]
Precedents:
In a rudimentary form, we already have a device similar to null-elimination operator - with spread collections, we can write:
[ ...?list]
- when "list" is null, nothing gets inserted. The proposal is consistent with this feature and takes it just one step further: if elimination makes sense for the list, it seems logical that it should make sense for a single value, too.Extra: a bit more controversial use case - in "if" statement, e.g.
if (?x) {...}
- same asif (x != null)
if (var x = ?(a?.b?.c)) { ... }
- like "let" in swift, but no new keyword is necessary, "var" works fineThe text was updated successfully, but these errors were encountered: