Null safety for properties and other operators

One notable difference between Gosu and some other languages is that property accessor paths in Gosu are null-tolerant, also called null-safe. Only expressions separated by period (.) characters that access a series of instance variables or properties support null safety, such as the following form:

obj.PropertyA.PropertyB.PropertyC

In most cases, if any object to the left of the period character is null, Gosu does not throw a null-pointer exception (NPE) and the expression returns null. Gosu null-safe property paths tend to simplify real-world code. Often, a null expression result has the same meaning whether the final property access is null or earlier parts of the path are null. For such cases in Gosu, do not check for the null value at every level of the path. This conciseness makes your Gosu code easier to read and understand.

For example, suppose you have a variable called house, which contains a property called Walls, and that object has a property called Windows. The syntax to get the Windows value is:

house.Walls.Windows

In some languages, you must be aware that if house is null or house.Walls is null, your code throws a null-pointer exception. The following common coding pattern avoids the exception:

// Initialize to null
var x : ArrayList<Windows> = null 

// Check earlier parts of the path for null to avoid a null-pointer exceptions (NPE)
if (house != null and house.Walls != null) {
  x = house.Walls.Windows
}

In Gosu, if earlier parts of a pure property path are null, the expression is valid and returns null. The following Gosu code is equivalent to the previous example and a null-pointer exception never occurs:

var x = house.Walls.Windows

By default, method calls are not null-safe. If the right side of a period character is a method call, Gosu throws a null-pointer exception (NPE) if the value on the left side of the period is null.

For example:

house.myaction()

If house is null, Gosu throws an NPE. Gosu assumes that method calls might have side effects, so Gosu cannot skip the method call and return null.

Gosu provides a variant of the period operator that is always explicitly null-safe for both property access and method access. The null-safe period operator has a question mark before the period: ?.

If the value on the left of the ?. operator is null, the expression evaluates to null.

For example, the following expression evaluates left-to-right and contains three null-safe property operators:

obj?.PropertyA?.PropertyB?.PropertyC

Null-safe method calls

A null-safe method call does not throw an exception if the left side of the period character evaluates to null. Gosu just returns null from that expression. Using the ?. operator calls the method with null safety:

house?.myaction()

If house is null, Gosu does not throw an exception. Gosu returns null from the expression.

Null-safe versions of other operators

Gosu provides null-safe versions of other common operators:

  • The null-safe default operator (?:). You use this operator to specify an alternative value if the value to the left of the operator evaluates to null. For example:
    var displayName = Book.Title ?: "(Unknown Title)" // Return "(Unknown Title)" if Book.Title is null
  • The null-safe index operator (?[]). Use this operator with lists and arrays. The expression returns null if the list or array value is null at run time, rather than throwing an exception. For example:
    var book = bookshelf?[bookNumber] // Return null if bookshelf is null
  • The null-safe math operators (?+, ?-, ?*, ?/, and ?%). For example:
    var displayName = cost ?* 2  // Multiply by 2, or return null if cost is null

Design code for null safety

Use null-safe operators where appropriate. These operators make code more concise and simplify the handling of edge cases.

You can design your code to take advantage of this special language feature. For example, expose data as properties in Gosu classes and interfaces rather than as setter and getter methods.

See also