Определение: Nullable (обнуляемый)
Тип в Haxe считается обнуляемым, если null является допустимым значением для него.
Обычно языки программирования имеют единое и весьма конкретное определение допустимости нулевых значений. Однако, Haxe вынужден искать в этом вопросе компромисс в связи с различной природой языков на которые будет транслироваться программ (будем называть такие языки целевыми). В то время, как некоторые из целевых языков допускают (и фактически используют как значения по умолчанию) null-значения, все остальные вообще не допускают null-значений для некоторых типов. Это требует разделения целевых языков на 2 группы по типизации:
- Определение: Статические целевые языки.
Статическими будем называть целевые языки, использующие статическую типизацию. Это группа языков, в которых переменные связываются с определенным типом данных в момент объявления. Таковыми являются, например, Flash, C++, Java, C#.- Определение: Динамические целевые языки.
Динамическими назовем те целевые языки для которых характерна динамическая типизация. Это группа языков, в которых переменные связываются с типом данных в момент присваивания им значения. Это, например, JavaScript, PHP, Neko, Flash 6-8.
Не о чем беспокоиться при работе с null для языков с динамической типизацией, так как в них переменные обнуляемы, в то время, как языки со статической типизацией требуют внимания.
При работе с языками со статической типизацией объекты базовых типов при создании могут быть инициализированы значениями по умолчанию.
Определение: Значения по умолчанию.
В языках со статической типизацией базовые типы имеют следующие значения по умолчанию:
- Int: 0
- Float: NaN на Flash, 0.0 на остальных статических целях
- Bool: false
Как следствие, компилятор Haxe не допускает присваивания null базовым типам в языках со статической типизацией. Чтобы сделать допустимым такое присваивание необходимо обернуть базовый тип следующим образом Null<T>:
1 2 3 |
var a:Int = null; // ошибка на платформах со статической типизацией var b:Null<Int> = null; // допустимо |
Таким же образом, базовые типы не могут быть сравнимы с null, если они не обёрнуты должным образом:
1 2 3 4 5 |
var a : Int = 0; while( a == null ) { ... } // на статических платформах предусловие не удовлетворяется, т.к. a не обёрнут в Null<Int> var b : Null<Int> = 0; if( b != null ) { ... } // допустимо, т.к. используется обёртка Null<Int> |
Это ограничение распространяется на все ситуации, где работает унификация.
На языках со статической типизацией Null<T>, Null<Bool>, Null<Float> могут быть использованы чтобы сделать допустимым null-значения. На языках с динамической типизацией это не будет иметь эффекта. Null<T> также может быть использовано с другими типами данных для указания того, что null-значение допустимо.
Если null-значение будет «скрыто» Null<T> или динамической типизацией, при присваивании базовому типу будет использовано значение по умолчанию:
1 2 3 4 5 6 7 |
var n : Null<Int> = null; var a : Int = n; trace(a); // 0 на статической платформе, так как a не обнуляем, var m : Null<Bool> = null; var b : Bool = m; b = m; trace(b); // false на статической платформе, так как b не обнуляем |
Подготовлено по материалам раздела Nullability официального учебника языка Haxe.