Константа box.NULL

Константа box.NULL

Имеется целый ряд серьезных проблем при использовании значения nil из Lua в таблицах. Например: вы не можете корректно оценить длину таблицы, не являющейся последовательностью.

Пример:

tarantool> t = {0, nil, 1, 2, nil}
---
...

tarantool> t
---
- - 0
  - null
  - 1
  - 2
...

tarantool> #t
---
- 4
...

Вывод в консоль t обрабатывает значения nil в середине и в конце таблицы по-разному. Это вызвано неопределённым поведением.

Примечание

Попытка найти длину для разреженного массива в LuaJIT приводит к другому случаю неопределённого поведения.

Для избежания этой проблемы используйте имеющуюся в Tarantool константу box.NULL вместо значения nil. box.NULL является местозаполнителем для значения nil в таблицах с целью сохранения ключа без значения.

Использование box.NULL

box.NULL является значением типа cdata, представляющим нулевой указатель (NULL pointer). Оно подобно msgpack.NULL, json.NULL и yaml.NULL. Таким образом, оно является некоторым не nil значением, даже если является указателем на NULL.

Используйте box.NULL только с NULL, написанным заглавными буквами (box.null является ошибкой).

Примечание

Технически, box.NULL соответствует ffi.cast('void *', 0).

Пример:

tarantool> t = {0, box.NULL, 1, 2, box.NULL}
---
...

tarantool> t
---
- - 0
  - null # cdata
  - 1
  - 2
  - null # cdata
...

tarantool> #t
---
- 5
...

Примечание

Заметьте, что t[2] демонстрирует один и тот же вывод null в обоих примерах. Однако, в данном примере t[2] и t[5] являются типом cdata, в то время как в предыдущем примере их тип был nil.

Важно

Избегайте использования неявных сравнений с обнуляемыми (nullable) значениямипри использовании box.NULL. В связи со штатным поведением Lua, возвращение любого результата, кроме false (ложь) или nil (ничто), из выражения условия считается возвращением true (истина). Как и упоминалось ранее, box.NULL является указателем.

Поэтому выражение box.NULL всегда будет расцениваться как true (истина) в случае использования в качестве условия в сравнении. Это означает, что код

if box.NULL then func() end

всегда будет выполнять функцию func() (потому, что условие box.NULL всегда будет не false (ложь) и не nil (ничто)).

Различение nil и box.NULL

Используйте выражение x == nil для проверки того, является ли x nil или box.NULL.

Для выяснения того, является ли x в действительности nil, но не box.NULL, используйте следующее условие:

type(x) == 'nil'

Если оно истинно (true), то x – это nil, но не``box.NULL``.

Вы можете использовать следующее выражение для box.NULL:

x == nil and type(x) == 'cdata'

Если вышеуказанное выражение истинно (true), то x – это box.NULL.

Примечание

Конвертируя данные в различные форматы (JSON, YAML, msgpack), вы должны ожидать возможного преобразования всех nil в разреженных массивах в box.NULL. Стоит ответить, что конвертация может происходить неожиданно (например: при отправке данных через net.box или при получении данных из спейсов и т.п.).

tarantool> type(({1, nil, 2})[2])
---
- nil
...

tarantool> type(json.decode(json.encode({1, nil, 2}))[2])
---
- cdata
...

Вы должны ожидать подобное поведение и использовать соответствующее выражение условия. Используйте явное сравнение x == nil для проверки на отсутствующее значение (NULL) в обнуляемых (nullable) переменных. Оно позволит обнаружить как nil, так и box.NULL.