Skip to main content

Null Safety

The Alia language provides null safety mechanisms to help developers avoid null value errors.

1. Null and Nullable Types​

Null is a standalone type that cannot participate in any operations (arithmetic, comparison, logical, etc.); operating on a Null value or a variable whose value is Null raises an error immediately. typeOf null returns 'Null'.

Use the ? suffix to declare a nullable type, meaning the value can be either the target type or Null.

Basic Syntax​

<Type?> ~ nullable type declaration

Example​

~ nullable string
const name: String? = null
const greeting: String? = 'Hello'

~ nullable number
const age: Number? = null
const count: Number? = 42

~ nullable object
const user: Object? = null

~ Null is a standalone type
print typeOf null ~ outputs 'Null'

2. The Ok Built-in Alias​

Ok is a built-in alias that checks whether a value is non-null, equivalent to typeOf val != 'Null', returning a Boolean. In contexts requiring explicit grouping, such as assert, write it as (Ok val).

Basic Syntax​

Ok <Value val> ~ returns a Boolean

Example​

const value1 = 'Hello'
const value2 = null

print Ok value1 ~ outputs true
print Ok value2 ~ outputs false

type User *[name: String]
const user: User? = *[name: 'Alice']
if Ok user {
print 'User exists: ' .. user.name
}

assert (Ok value1)

3. Nullable Parameters​

In an alias declaration, <Type? argName> declares a nullable parameter, allowing null to be passed.

Basic Syntax​

alias <Type? argName> -> { argName }

Example​

~ nullable string parameter
alias greet <String? name> -> {
if Ok name {
print 'Hello, ' .. name
} else {
print 'Hello, stranger'
}
}

greet 'Alice' ~ outputs 'Hello, Alice'
greet null ~ outputs 'Hello, stranger'

~ multiple nullable parameters
alias createUser <String? name> and <Number? age> -> *[name: String, age: Number] {
const realName = name ?? 'Anonymous'
const realAge = age ?? 0
return *[ name: realName, age: realAge ]
}

const u1 = call createUser ['Bob', 25]
print u1.name ~ outputs 'Bob'
print u1.age ~ outputs 25

const u2 = call createUser [null, null]
print u2.name ~ outputs 'Anonymous'
print u2.age ~ outputs 0

~ mixing nullable and non-nullable parameters
alias divide <Number a> <Number? b> -> Number {
if Ok b {
if b == 0 { return 0 }
return a / b
} else {
return 0
}
}

print call divide [10, 2] ~ outputs 5
print call divide [10, null] ~ outputs 0

4. The Null Coalescing Operator​

?? returns the right-hand value when the left-hand side is null, and the left-hand value otherwise.

Basic Syntax​

<Value left> ?? <Value right>

Example​

~ basic usage
const name = null
const displayName = name ?? 'Anonymous user'
print displayName ~ outputs 'Anonymous user'

const count = 42
const displayCount = count ?? 0
print displayCount ~ outputs 42

~ chained usage
const value = null ?? null ?? 'Default value'
print value ~ outputs 'Default value'

5. Comprehensive Example​

~ comprehensive null safety example

~ 1. nullable type declarations
const username: String? = null
const age: Number? = 25

~ 2. checking with Ok
if Ok username {
print 'Username: ' .. username
} else {
print 'Username is empty'
}

~ 3. providing defaults with ??
const displayName = username ?? 'Anonymous user'
print 'Display name: ' .. displayName

~ 4. nested nullable objects
type User *[name: String, email: String?]
const bob: User? = *[name: 'Bob', email: 'bob@example.com']
const guest: User? = null

if Ok bob {
print 'Email: ' .. (bob.email ?? 'default@example.com')
} else {
print 'User is empty'
}

const fallback: User = guest ?? *[name: 'Guest', email: null]
print 'Display name: ' .. fallback.name

6. Best Practices​

6.1 Prefer Nullable Types​

~ recommended: declare nullable return types explicitly
alias findUser <Number id> -> Object? {
if id > 0 { return *[id: id] }
return null
}

const user: Object? = findUser 1

6.2 Use ?? to Provide Sensible Defaults​

~ recommended: provide meaningful defaults
const config = *[timeout: null, retries: null]
const timeout = config.timeout ?? 3000
const retries = config.retries ?? 3

6.3 Use Ok for Existence Checks​

~ recommended: check that a value exists before operating on it
const result = null
if Ok result {
print 'Operation succeeded: ' .. result
} else {
print 'Operation failed'
}

Next Steps​