Open EliteMasterEric opened 6 months ago
Some more niche concerns:
While I was reading through the Python proposal linked in #89, I found an additional piece of syntax they specify. The ??=
syntax evaluates the left-hand side, determines if its value is null, and only performs an assignment if it is.
// Before
if (value == null) value = 4;
// Note this line is not technically equivalent, as it calls set_value if value is a property.
value = value ?? 4;
// After
value ??= 4;
I personally find this syntax to pretty redundant, as unlike with Python, Haxe can represent the expression in a single line. Thus, it would only reduce the readability of code, at least for those who were not aware of the syntax. Wanted to bring it up just in case someone else thinks there's a worthy case to be made for it.
It was mentioned during the main implementation of safe navigation that overloads of the ==
operator are ignored when evaluating safe navigation. This made me realize that handling of operator overloads for safe navigation and null coalescing might not be implemented.
Thankfully, @:op(a?.b)
is considered valid, however when attempting to assign @:op(a ?? b)
, the compiler outputs this message:
Null coalescing overloading is not supported
I think support for this should be considered in the future, since as stated, the ==
overload is not used when evaluating ??
.
Currently object1?.object2?.myFunction()
should work if myFunction
is non-nullable in object2
(just a reminder). Nullable array access is a more common case, i guess.
??=
is already implemented with null coalescing op, not sure if you suggested to remove it.
I think ??
overloading was not implemented because this operator is right-associative, so it can create problems if you don't know about it when overloading.
Note that when I called the syntax awkward, I was referring to the ?[]
version. The ?.[]
version looks even more ridiculous to me, the point where I prefer to not see it in the language unless there's a very convincing use-case. IMO if you're working with nested nullable arrays then you went wrong somewhere in your design/life.
For example, Dart also doesn't have ?(
/?[
syntaxes and uses fn?.call()
or arr?.get(0)
/ set()
methods. This is already can be implemented for arrays in user static extensions, doesn't look much worse than ?.[
for me.
But fn?.call()
means (fn != null) ? fn.call() : null
.
For deeply nested nullable arrays I would suggest creating an abstract over Null<Array<T>>
and defining null safe array access therein.
For deeply nested nullable arrays I would suggest creating an abstract over
Null<Array<T>>
and defining null safe array access therein.
Does this work on, say, arrays provided by JSON?
Sure. Abstracts are a compile time only feature.
Here is an example:
class Test {
static function main() {
var x:{?board:NullableArray<NullableArray<Int>>} = haxe.Json.parse("{}");
trace(x?.board[1][2] == null);// true
}
}
abstract NullableArray<T>(Array<T>) {
#if (js && js_es == 6)
@:op([]) inline function get(i:Int):Null<T>
return js.Syntax.code('{0}?.[{1}]', this, i);
#else
@:op([]) function get(i:Int):Null<T>
return
if (this == null) null
else this[i];
#end
}
I wanted to make a new home for a topic of discussion that is somewhat dispersed right now.
Safe navigation was implemented for object field access in 4.3.0, however it was not implemented for array access or function calls, despite being included in the original proposal #89 .
Array Access
The original proposal dictated that accessing
nullArray?.[0]
would return null, as opposed tonullArray[0]
which currently throws a TypeError.This syntax is notably useful in cases where you are working with nested arrays, like
nullArray?.[i]?.[j]?.[k]
. The fallback behavior is also very clear.The syntax of
?.[]
is used over?[]
since the latter is indistinguishable from a ternary operator by the parser. This syntax would notably be shared with Javascript and no other language.Function Calls
The original proposal dictated that accessing
nullFunction?.()
would return null, as opposed tonullFunction()
which currently throws a TypeError.This syntax is notably useful primarily in the case where you are performing multiple object chaining operations in one line, such as
object1?.object2?.myFunction?.()
. It also may be used in the case where you use an optional callback function.The main reasoning behind these not being implemented with the original proposal, as stated here: https://www.youtube.com/watch?v=lkpoTcHKjSE&t=454s