Rouge Documentation Help

Absence or presence of values

Variables, fields, or parameters can have different data types, and therefore many possible values within those respective data types. For instance, a variable may be of type Number, in which case you can set its value to be any number you can imagine. However, at this point in the course we have not talked about the possibility that values can be absent. Consider the following example, where a Person has a name and a phone number.

type Person { name: String, phone_number: Number, }

Using this implementation, every person has to have a phone number. However, our implementation should also apply to people that don't have a phone. Therefore, we need to adjust the implementation so that the value in the phone_number field may be absent. To achieve this, we can wrap the address in the Optional type from the standard library.

The following type diagram illustrates how the Optional type works. Each box in the diagram represents a type, with traits being explicitly marked as such. Optional is a trait with two implementations called Something and Nothing, representing the presence or absence of a value respectively. In the diagram, an arrow pointing from a type to a trait signals that the type implements the trait. When a type implements methods that are dictated by a trait, they are only shown in the trait, even though they can, of course, be called on the implementing types as well. This is not a given for all diagrams of this kind; rather, this is done to keep diagrams in this course concise.

«trait»
Optional<T>
has_value() -> Boolean
get_value() -> T
...
Nothing<T>
Something<T>
value: T

Optional has a placeholder called T which represents the type of the value, in case it is present. The type called Something wraps a value of type T, while its counterpart called Nothing does not contain a value at all. We can apply these new types to our initial example by changing the type of the field phone_number from Number to Optional<Number>.

type Person { name: String, phone_number: Optional<Number>, }

Now, when we are instantiating a Person, we can choose to set phone_number to an instance of Something, in case the person has a phone (and therefore a phone number). On the other hand, if the person does not own a phone, we can set the field to an instance of Nothing.

steve = Person( "Steve", Something(123456789), ) bella = Person( "Bella", Nothing(), )

Accessing the value potentially stored in an Optional is a bit more complicated, however. First, we need to check whether an instance of Optional does or doesn't contain a value. To achieve this, we can use the method called has_value, which returns true in case of type Something and false in case of type Nothing. Only after we have checked for this condition, we can access the value stored inside by calling get_value. The following example demonstrates how to properly access the value stored inside an Optional.

print_personal_details = function(person: Person) { name = person.name print("The person is called ${name}.") if (person.phone_number.has_value()) { phone_number = person.phone_number.get_value() print("${name} can be reached at ${phone_number}.") } else { print("${name} does not have a phone.") } } print_personal_details(steve) print_personal_details(bella)

Output:

The person is called Steve. Steve can be reached at 123456789. The person is called Bella. Bella does not have a phone.

In theory, nothing prevents you from calling get_value without checking whether the Optional contains a value first. However, calling get_value on an instance of Nothing will produce an unrecoverable error causing your entire program to crash. Therefore, it is recommended that you always call has_value before get_value.

Last modified: 07 January 2026