HaxeFoundation / haxe-evolution

Repository for maintaining proposal for changes to the Haxe programming language
111 stars 58 forks source link

Null coalescing operator #85

Closed RblSb closed 2 years ago

RblSb commented 3 years ago

Rendered version

RealyUniqueName commented 3 years ago

I find this useful. Null check + default value is quite common operation. And null coalescing would play nicely with null safety feature because of the typing:

var s:Null<String> = getNullableString();
$type(s == null ? 'default value' : s); // Still `Null<String>`
$type(s ?? 'defaultValue'); // would yield `String`
grepsuzette commented 3 years ago

Seeing Haxe more and more as very high-level language, it would be a nice thing to have.

But I favour the ?: variant for 2 reasons:

  1. ?: is very consistent with the ternary operator, making it quite logical.
  2. to me ?? is typographically ugly, reminiscent of hastly written scripts (with ????!!! debug traces all over the place), distracting programmer.

Consider:

function main() {
    var x : Null<Foo> = getFoo();
    var o = { foo : x ?: Foo.empty() }
}

vs

function main() {
    var x : Null<Foo> = getFoo();
    var o = { foo : x ?? Foo.empty() }
}

The first variant jumps much less at your eyes IMO. More relaxing maybe.

Edit: note according to this source Kotlin has no ternary operator. Yet it still uses the ?: operator for null coalescing. This despite the fact it has abundant usage of ? and !. This might be another reason to double-think the usage of ?? for this evolution.

grepsuzette commented 3 years ago

Reading about ?: on https://en.wikipedia.org/wiki/Elvis_operator there is also the historical usage for the Elvis ?: operator, like in C++ or PHP. tl;dr it couldn't be useful in Haxe because in these languages the concept of evaluating to true is so much less restrictive.

The name "Elvis operator" refers to the fact that when its common notation, ?:, is viewed sideways, it resembles an emoticon of Elvis Presley with his quiff.[1]

A similar operator is the null coalescing operator, where the check for boolean truthiness is replaced with a check for non-null instead. This is usually written ??, and can be seen in languages like C# (or Typescript).

In short, the usage of ?: in C++ and PHP is to repeat the preceding result (for instance var x = f() ?: g() is equivalent to var x = f() ? f() : g(), but without evaluating f() a second time). In C++ for example a non-empty string, non-zero int, or a non-null object would evaluate to true making this very useful.

In Haxe, since nothing can evaluate to Bool implicitely, there would be no such use; hence we could not use it at all, or use it for null coalescing. C# also has ??=, which is overkill IMO. But if you think differently it can be an argument for ??, since ?:= looks like the skull of Elvis Presley.

Aurel300 commented 3 years ago

C# also has ??=, which is overkill IMO.

Well, if ?? becomes a binary operator, I don't see a reason to disallow it in OpAssignOp for the ??= combination. It shouldn't have the short-circuiting issues of ||= and &&=. Besides, I find it pretty common to need to assign a default value if something is null.

grepsuzette commented 3 years ago

Fair enough, but the point of null coalescing operator is to reduce the LOC and the number of intermediate variables; that is why I think it is not as useful.

Besides, p ??= Foo.empty(); is less clear than if (p == null) p = Foo.empty(); I think, or than p = p ?: Foo.empty().

Let's see:

pWindow ??= Foo.empty();

if (pWindow == null) pWindow = Foo.empty();

pWindow = pWindow ?: Foo.empty();

pWindow = pWindow ?? Foo.empty();

But it's probably a matter of practice, and in the end maybe you are in the right.

RblSb commented 3 years ago

I would like to have many things from Kotlin, but when wiki says

This is an unusual choice of symbol, given that ?: is typically used for the Elvis operator, not null coalescing, but it was inspired by Groovy (programming language) where null is considered false.

I would stick on C#/JS/etc option. Even if it looks more strange - it's pretty common and easier to type. Also don't think that ternary operator and null coalescing are that similar, so we shouldn't unify it to same syntax. ??= seems interesting, but i'm not brave enough to request this feature for now, something like this.x = y ?? this.x looks good enough.

YellowAfterlife commented 3 years ago

C# also has ??=, which is overkill IMO ??= is perfect for non-constant default argument values, e.g.

function filter(fn:T->Bool, ?out:Array<T>):Array<T> {
out ??= [];
for (item in items) if (fn(item)) out.push(item);
return out;
}

allowing to both call the function as-is to allocate a one-off array and to call it with an existing array to concat items to the end of it.

a = a ?? b introduces a bit of redundancy in comparison as we are reassigning a (which can be more complex than a local variable) even if it was fine.

nickmain commented 3 years ago

Another vote for "??" since that is what Swift uses.

lublak commented 3 years ago

Especially the null-safe traversal operator would make a lot of sense when working with json files.

return options?.advanced?.id ?? 0;

vs

return options == null ? 0 : (options.advanced == null ? 0 : (options.advanced.id == null ? 0 : options.advanced.id));

or

return options == null || options.advanced == null || options.advanced.id == null ? 0 : options.advanced.id;
Simn commented 2 years ago

This proposal has been accepted, see https://haxe.org/blog/evolution-meeting-2021/ for details.