language icon indicating copy to clipboard operation
language copied to clipboard

More null-aware operators (comparison & assignment)

Open Reprevise opened this issue 5 months ago • 2 comments

I'm truly sorry if this issue is a duplicate, I tried searching for this but I couldn't find anything. Maybe I don't know enough language jargon.

Take this Dart code:

int? value = getValue();
if (value > 0) { // operator > can't be unconditionally invoked because the receiver can be 'null'
  print("greater than 0");
}

So, we can't do if (bool?), only if (bool), which makes sense. However, it would be convenient if there were null-aware comparison operators. Surely we can get more use of the ? right guys?

Currently, you can do:

int? value = getValue();
if ((value ?? 0) > 0) { // doesn't work without nested parenthesis
  print("greater than 0");
}

but it's a bit messy, in my opinion.

Idea:

Explicit

My main idea is just to place the question mark either before or after an operator symbol like so: value ?> 0 which would only continue if value is NOT null.

// To be clear, both of these operators do the same thing, I'm just proposing one or the other
// depending on what makes more sense (the position of the '?'.)

// Unless, there's significant interest in introducing both of these operators and
// having them behave differently (one guards against null and the other allows null.)
if (val >? 0) {}
if (val ?> 0) {}

Implicit

Alternatively, we could just have this behavior for operators right now, like what C# does:

int? val = null;
if (val > 0) { // no error
  Console.WriteLine("greater than 0"); // doesn't run
} else {
  // this runs instead
}

I'm not sure how breaking that would be though.

Assignment:

We can also do this for assignment operators:

int? val = null;
val ?+= 10; // Only adds 10 if 'val' is NOT null
val ?-= 10;
val ?*= 10;
val ?/= 10;

Reprevise avatar Jul 14 '25 22:07 Reprevise

It's not new to want some null awareness with operators. Not sure this precise version has been suggested as its own issue before. (I cannot find things using GitHub search either.)

An immediate issue with if (val ?> 0) … is that the obvious value of that expression of val is null is null, and null is not valid where a bool is required.

There are ways to fix that:

  • Allow null to mean false in any condition. That's error-prone.
  • require you to write (val ?> 0) ?? false. That's more verbose, closer to where you could just write val != null && val > 0.
  • say that val ?> 0 evaluates to false if val is null. But > is user-definable, it doesn't have to return bool.
  • Not allow it, and defer to patterns: val case >0?.

My favorite if we were to generalize null-awareness:

  • introduce "null aware context"s that catch null-checks and define what they mean.
  • let ?expr, and expr? followed by a selector or operator, be an expression, which bails out to the nearest surrounding null aware context if the value is null.
  • a condition context would introduce a null-aware context which converts a null-bailout to false.
  • a null-aware selector will introduce a null-aware context for the rest of the chain, if not already inside one, which converts bailout to null, like today's foo?.bar(), but also allowing foo?.bar(?val).
  • elements are null-aware contexts that omit the element on bailout, like today's [?val], but also [foo(?val)].
  • you can introduce an explicit null-aware context using (?expr), so any failing null-aware check inside will bail out to this expression and evaluate to null.

Assignment expressions may still need their own syntax, or expr?+= could preserve expr being assignable, only affecting the read of the composite operation.

lrhn avatar Jul 15 '25 05:07 lrhn

this one is very usefull

makri-aymen avatar Oct 08 '25 09:10 makri-aymen