# More consistent null handling

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

Source: https://orbitalhq.com/blog/2025-07-17-changes-to-nulls
Date: 2025-07-17

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:

Schema:

```taxi
type Surname inherits String
type GivenName inherits String
model Person {
  givenNames: GivenName[]
  surname: Surname
}
```

Query:

```taxi
given { Person = null}
find { Person } as {
    givens : GivenName[] 
    surname : Surname
}
```

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

Schema:

```taxi
type Surname inherits String
type GivenName inherits String
model Person {
  givenNames: GivenName[]
  surname: Surname
}
```

Query:

```taxi
given { Person = null}
find { Person ?: {} } as {
    givens : GivenName[] 
    surname : Surname
}
```

You can also coalesce individual properties:

Schema:

```taxi
type Surname inherits String
type GivenName inherits String
model Person {
  givenNames: GivenName[]
  surname: Surname
}
```

Query:

```taxi
given { Person = null}
find { Person ?: {} } as {
    givens : GivenName[] ?: ['Jimmy','McJimmyFace' ] 
    surname : Surname ?: 'Schmitt' 
}
```

## New StdLib functions

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

### `ifEmpty()` 
[Docs](https://taxilang.org/docs/language/stdlib#if-empty)

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

Schema:

```taxi
type Name inherits String
```

Query:

```taxi
import taxi.stdlib.ifEmpty
given {
    noStrings: String[] = null,
    emptyStrings: String[] = [],
    emptyNames: Name[] = []
}
find {
    a: String[] =  noStrings.ifEmpty(['Hello']) // returns null
    b: String[] = emptyStrings.ifEmpty(['Hello']) // returns ['Hello']
    c: Name[] = Name[].ifEmpty(['Jimmy']) // declared against the type, returns ['Jimmy']
}
```

### `emptyInstance()`
[Docs](https://taxilang.org/docs/language/stdlib#empty-instance)

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**

Schema:

```taxi
model Person {
   name : Name inherits String
   friends : Person[]
   address: {
      houseNumber : HouseNumber inherits String
      streetName : StreetName inherits String
   }
}
```

Query:

```taxi
given { p:Person = null }
find { person : Person ?: Person.emptyInstance()}
```

**emptyInstance() in an array**

Schema:

```taxi
model Person {
   name : Name inherits String
   friends : Person[]
   address: {
      houseNumber : HouseNumber inherits String
      streetName : StreetName inherits String
   }
}
```

Query:

```taxi
import taxi.stdlib.emptyInstance
given { p:Person[] = null }
find { 
    people : Person[] ?: [Person.emptyInstance()]
}
```
