Coding Rules

Rules for writing robust, maintainable code

Rule 2: Don't use sentinel values if your language has a better alternative

A sentinel value is a value such as -1 or the empty string, that has a special meaning in the context of a program.

Sentinel values are undesirable because:

  • It isn't obvious that a type contains a sentinel value, which may result in new code not handling the sentinel value without getting a compiler error or looking obviously wrong.

  • Mistakes or future changes may result in sentinel values colliding with real values.

A better option is to use an adequate composite type such as a union type.

āŒ Don't:

/* endDate: the unix time or -1 if there is no end date */
function isDateValid(date:number endDate: number) {
    return date < endDate || endDate === -1;
}

The above code is wrong because Unix times can be negative: -1 is both a real date and the sentinel value.

It is also brittle, as the condition could have been implemented as only date < endDate without looking obviously wrong or causing a compiler error.

āœ… Do:

function isDateValid(date: number, endDate: number | null) {
  return endDate === null || date < endDate;
}
fn is_date_valid(date:i64, end_date: Option<i64>) -> bool {
    match endDate {
        Some(x) => date < x,
        None => true,
    }
}

Even without comments, it is clear that there may or may not be an end date.