Movatterモバイル変換


[0]ホーム

URL:


Tail Recursion Elimination (TRE)Warnings

8.9 Null Safety

since Haxe 4.0.0

The Haxe compiler offers opt-in compile-time checking for nullable values. It attempts to catch various possible issues with nullable values.

Enabling Null Safety

To enable the checker for a particular class, field, or expression, annotate it with the:nullSafety metadata. Null safety can be enabled for a whole package using the--macro nullSafety("some.package")initialization macro.

Strictness

There are four levels of null safety strictness:

  • Off: Turn off null safety checks. Useful to selectively disable null safety for particular fields or expression.
  • Loose (Default): Within anif (<expr> != null) condition,<expr> is considered safe even if it could be modified after the check.
  • Strict: Full-scale null safety checking for a single-threaded environment.
  • StrictThreaded: Full-scale null safety checking for a multi-threaded environment.

Enabling null safety by default uses the loose strictness level. This can be configured by providing an argument in the metadata:

@:nullSafety(Off)@:nullSafety(Loose)@:nullSafety(Strict)@:nullSafety(StrictThreaded)

Strict andStrictThreaded differ in handling of sequential field access.In a multi-threaded application sequential access to the same object field may not yeld the same result. That means a null check for a field does not provide any guarantees:

@:nullSafety(StrictThreaded)functiondemo1(o:{field:Null<String>}) {if (o.field !=null) {// Error: o.field could have been changed to `null`// by another thread after the checktrace(o.field.length);  }}@:nullSafety(Strict)functiondemo1(o:{field:Null<String>}) {if (o.field !=null) {trace(o.field.length);// Ok  }}

For the package-level case, null safety strictness can be configured using the optional second argument:

--macronullSafety("some.package",Off)--macronullSafety("some.package",Loose)--macronullSafety("some.package",Strict)--macronullSafety("some.package",StrictThreaded)
Detailed Usage
  • Null safety makes sure you will not pass nullable values to the places which are not explicitly declared withNull<T> (assignments, return statements, array access, etc.).
@:nullSafetyclassMain {staticfunctiongetNullableStr():Null<String> {returnnull;  }publicstaticfunctionmain() {functionfn(s:String) {}varnullable:Null<String> =getNullableStr();// all of the following lines would cause a compilation error:// var str:String = null;// var str:String = nullable;// fn(nullable);  }}
  • Using nullables with unary and binary operators (except== and!=) is not allowed.
  • If a field is declared withoutNull<> then it should have an initial value or it should be initialized in the constructor (for instance fields).
  • Passing an instance of a parametrized type with nullable type parameters where the same type with non-nullable type parameters is expected is not allowed:
varnullables:Array<Null<String>> = ['hello',null,'world'];// Array<Null<String>> cannot be assigned to Array<String>://var a:Array<String> = nullables;
  • Local variables checked againstnull are considered safe inside of a scope covered with that null-check:
varnullable:Null<String> =getSomeStr();//var s:String = nullable; // Compilation errorif (nullable !=null) {s =nullable;//OK}//s = nullable; // Compilation errors = (nullable ==null ?'hello' :nullable);// OKswitch (nullable) {casenull:case_:s =nullable;// OK}
  • Control flow is also taken into account:
functiondoStuff(a:Null<String>) {if(a ==null) {return;  }// From here `a` is safe, because function execution// will continue only if `a` is not null:vars:String =a;// OK}
Limitations
  • Out-of-bounds array reads returnnull, but Haxe types them withoutNull<>.
vara:Array<String> = ["hello"];$type(a[100]);// Stringtrace(a[100]);// nullvars:String =a[100];// Safety does not complain here, because `a[100]` is not `Null<String>`, but just `String`
  • Out-of-bounds array writes fill all positions between the last defined index and the newly-written one withnull values. Null safety cannot protect against this.
vara:Array<String> = ["hello"];a[2] ="world";trace(a);// ["hello", null, "world"]vars:String =a[1];// Cannot check thistrace(s);//null
  • Haxe was not designed with null safety in mind, so it's always possiblenull values will come into your code from third-party code or even from the standard library.
  • Nullable fields and properties are not considered null-safe even after checking againstnull. You can use helper methods instead:
usingMain.NullTools;classNullTools {publicstaticfunctionsure<T>(value:Null<T>):T {if (value ==null) {throw"null pointer in .sure() call";    }return @:nullSafety(Off) (value:T);  }publicstaticfunctionor<T>(value:Null<T>,defaultValue:T):T {if (value ==null) {returndefaultValue;    }return @:nullSafety(Off) (value:T);  }}classMain {staticvarnullable:Null<String>;publicstaticfunctionmain() {varstr:String;if (nullable !=null) {str =nullable;// Compilation error    }str =nullable.sure();str =nullable.or('hello');  }}
  • If a local variable is captured in a closure, it cannot be safe inside that closure:
vara:Null<String> =getSomeStr();varfn =function () {if (a !=null) {vars:String =a;// Compilation error  }}

Unless the closure is executed immediately:

vara:Null<String> =getSomeStr();[1,2,3].map(function (i) {if (a !=null) {returni *a.length;// OK  }else {returni;  }});
  • If a local variable is captured and modified in a closure with a nullable value, that variable cannot be safe anymore:
varnullable:Null<String> =getSomeNullableStr();varstr:String;if (nullable !=null) {str =nullable;// OKdoStuff(function ()nullable =getSomeNullableStr());if (nullable !=null) {str =nullable;// Compilation error  }}


[8]ページ先頭

©2009-2025 Movatter.jp