More consistent null handling

We're fixing edge cases and standardizing how null is treated

Marty Pitt@marty_pitt

There are some important changes coming in 0.36 around how null is treated in a projection, to be more consistent.

Previously, we were inconsistent (and sometimes, just flat-out wrong) with how null was treated:

  • Sometimes null would return null
  • Sometimes null would return an empty list
  • Sometimes null would return a list containing an object, but everything was null 🤯

Also, for legacy reasons, the behaviour was different depending on where the null was encountered (the “find” phase of a query, vs a projection)

As of 0.36, the rule is simply:

A value of null always projects to null

There’s a few places where this behavior is different from previous versions:

  • Services that return an empty response, like an HTTP 204, used to be treated as a special empty object - but is now returned as null
  • Services that are declared to return an array, and return an empty response (like an HTTP 204), used to result in an array of an empty object - it now correctly returns null

For example - this snippet now (correctly) fails, whereas previously it would return an empty object:

Use coalesce

Generally speaking, if you have a null, and want something other than null returned, you can coalesce it, using the ?: operator:

You can also coalesce individual properties:

New StdLib functions

We’ve added some new functions to the StdLib to provide backwards compatability, for those who require it.

ifEmpty()

Docs

An extension function against collections, that returns the default if the provided value is empty.

emptyInstance()

Docs

There’s now an emptyInstance() member, which will return an instance of the requested type, but where:

  • Scalars are null
  • Collections are []
  • Objects are recursed into, applying the above rules

This is useful where type coercion matters.

  • The type of Person ?: {} is Any
  • The type of Person ?: Person.emptyInstance() is Person
  • The type of Person[] ?: [{}] is Any[]
  • The type of Person[] ?: [Person.emptyInstance()] is Person[]

emptyInstance() on a single item

emptyInstance() in an array