I wanted to bring @:nullSafety into one of my projects, which has a lot of @:optional fields. In order to make it easier I thought to use abstracts for the nullable fields which handle the null case.
for example for Null<Float>
@:nullSafety
abstract OFloat(Null<Float>) from Null<Float> to Null<Float> {
public inline function val(): Float return this != null ? this : 0.0;
@:op(A + B) static inline function addOp1(lhs: OFloat, rhs: Float): Float {
return lhs != null ? lhs.val() + rhs : rhs;
}
}
@:nullSafety
class Test {
static function main() {
var x: OFloat = null;
trace(x.val()); // works
$type(x.val()); // Float
var xx = x.val(); // error Null safety: Cannot assign nullable value here.
x = x + 1.0; // error Null safety: Cannot perform binary operation on nullable value.
}
}
strange here that trace(v.val())
works. I guess it is some trace magic.
When I make val()
static it works:
using Test.OFloat;
@:nullSafety
abstract OFloat(Null<Float>) from Null<Float> to Null<Float> {
public static inline function val(v: OFloat): Float return v != null ? v : 0.0;
@:op(A + B) static inline function addOp1(lhs: OFloat, rhs: Float): Float {
return lhs != null ? lhs.val() + rhs : rhs;
}
}
@:nullSafety
class Test {
static function main() {
var x: OFloat = null;
trace(x.val()); // works
$type(x.val()); // Float
var xx = x.val(); // works
x = x + 1.0; // works
trace(x);
}
}
now I understand that currently the only way to operate on a Null<T>
is with static extensions, but since abstracts are different and the value of this
can be checked against null
before any operation on this
shouldn’t this be allowed when the abstract is checked by the compiler with @:nullSafety ?
Anything that can happen, will happen inside the abstract (forwarded functions are of course only that safe they were before):
abstract OFloat(Null<Float>) from Null<Float> to Null<Float> {
@:nullSafety
public inline function valBad(): Float return this; // error Null safety: Cannot return nullable value of Null as Float
@:nullSafety
public inline function valGood(): Float return this != null ? this : 0.0; // ok
}
So from outside the abstract it should be safe to use x.valGood()
what do you think ?
Adrian.