# Nullable types

If you see a type with a question mark at the end – such as **boolean?** – then you are looking at a *nullable type.* The nullable version of a type adds the ability for a variable to have the value **null**. Variables of nullable types may be created using [explicit type annotations](https://docs.novacura.com/flow-connect/reference/reference/flowscript/variables#advanced-explicit-type-annotations), by [evolution](https://docs.novacura.com/flow-connect/reference/reference/flowscript/variables#advanced-evolving-variable-types), or from other steps such as User steps. For instance, **Numeric input** items with the **Allow Empty Input** option enabled create values of type number? (which can be pronounced "nullable number").

Only variables with nullable types can have the value null.

```typescript
// Example 1: create a nullable variable by evolution.
let x = null;
set x = 1;

// Example 2: create a nullable variable by explicit type annotation.
let y: number? = 1;
set y = null;

// Example 3: create a non-nullable variable.
let z = 1;
set z = null; // ERROR: Expected a 'number' but the term has type 'null'.
```

### Refining nullable values

A non-nullable type is always compatible with its nullable counterpart, but a nullable type is not compatible with its non-nullable counterpart. Many common operations in FlowScript are only defined for non-null values. Therefore, nullable values must often be *refined* before you can work with them.

One such example is the multiplication operator, which works with numbers but not nullable numbers:

```typescript
// Example: we imagine that we have received an non-local variable "totalPrice"
// which is a nullable number. We try to use the variable in a calculation.
// This gives a design-time error.

// ERROR: Expected a 'number' but the term has type 'number?'
let discountedPrice = totalPrice * 0.8;
```

To calculate the discounted price, we must refine the **totalPrice** variable. In other words, we must decide what the discounted price will be if the total price is null. We do this using a *null guard expression*:

```typescript
let discountedPrice = 0;

if totalPrice != null {
   // Because this code is only run when totalPrice is not null,
   // there is no error here.
   set discountedPrice = totalPrice * 0.8;
}
```

In the example above, FlowScript is analyzing the program to deduce that totalPrice can be safely multiplied with another number inside the if-branch. The act of using a null guard expression on a variable temporarily changes its type in the parts of the program guarded by the expression.

<details>

<summary>Advanced: More on null guards</summary>

What constitutes a null guard expression? The equation, inequation and type narrowing operators can all be used to refine a value:

```typescript
if x != null {
    // x is refined to not-null here
}

if not (x == null) {
    // x is refined to be not-null here
}

if not (x is null) {
    // x is refined to be not-null here
}
```

In each of the examples above, the code inside the if block is only executed if the variable is not null. FlowScript keeps track of this when type-checking the program.

Null guards can also be used in case expressions, or in conjunction with the return or error statements.

```typescript
if totalPrice == null:
    return 0;

// We would not reach this line of code
// if totalPrice was null, so we are allowed to use it in multiplication.
return totalPrice * 0.8;
```

Several null guards may combined using the **and** keyword as expected:

```plsql
if x != null and y != null {
    return x * y;
}
```

</details>

## Primitive
