Dodo doc > Variables and Functions > Linked References


Linked References

A link is an object that can be shared to establish a relationship between several objects. If a value is associated with the link it is called a linked reference.

Linked references are often used to store values that are shared by more than one object instance. A linked reference can also be used in a function, where an argument by reference cannot.

Requirements

To use linked references, the dodo file should contain:

use link
Rationale: Linked references are provided as a service, and no service namespace is included by default in dodo programs. So the namespace needs to be included manually.

Declaration

Linked references are variables or constants of type "Link" with a target type. If they don't have an initial value, their initial state is "null" and they cannot be converted to the target type. The Link constructor is used to create a linked reference with an initial value.

Examples:

Link(<with: House>) property  # initially null
def number = Link(10)
Rationale: Link is a capability type provided by the link service. Being a capability is what allows the variable to be used in a function when a reference can not. Apart from shared storage, another use of linked references is to allow side effects in functions.
By default, a linked reference state starts as "null" for times when it is desirable that the value is uninitialised first. This mimics the behaviour of references in other languages.

Use in expressions

Where necessary, dodo converts a linked reference to its target type so it can be used in the same way as the target type. A linked reference in "null" state cannot be converted to its target type and using it the same way raises an exception.

Examples:

draw(paper, property)  # Exception
2 * number
Rationale: It is clear why an exception is raised when trying to use an uninitialised value. Automatic conversion to the target type allows a lighter syntax than explicit conversion.

Use as argument by reference

Passing a variable by reference never involves a conversion. Because a Link variable is not of the same type as the target, linked references have a special syntax that allow the operation to use directly the target so no conversion is required.

That special syntax is to prefix the variable name with "link!".

Examples:

.link!property = showHome
GenerateNumber(.link!number)
Rationale: The alternative is to pass a reference to the Link variable itself, which prevents from using it when the target type would be expected and raises other concerns. In particular the linked reference would stop being shared when giving a new value by assignment.
The dodo syntax makes it clear which service the capability belongs to.

Storage and activation

When a linked reference is copied to a different Link variable the copy becomes inactive. Using it as argument by reference raises an exception. The copy can be reactivated with the Activate() method.

Example:

.self.house = property  # inactive
self.house.Activate()

A function declaration can include an active linked reference parameter. Its type is prefixed with "*" to mark it as active.

When calling the function the variable name needs to be prefixed with "*" too.

Example:

def addToDirectory(*Link(<with: Directory>), Link(<with: House>), Details)

addToDirectory(*directory, house, details)
Rationale: In general it is preferable to prevent side effects in functions. As storing a linked reference in an object can allow side effects in member functions, it is made inactive to prevent them.
Since the Activate() method can only be invoked in a method or constructor, that means the paths that lead to side effects in functions always originate from parts of code where side effects are allowed.
An active linked reference allows side effects which is why they are prefixed with a star.

Finding linked references

If there is a list of objects "directory" with a linked reference attribute house, the objects that link to a particular reference property can be found with:

directory[where house = property]
Rationale: This equality compares the links rather than the target objects which ensures the directory entries are linked to the selected reference.

Joining two lists by a linked reference

If the objects in a first list directory are related to the objects in a second list street by sharing a linked reference house, the two lists can be joined together with:

[for entry in directory; for address in street; where entry.house = address.house]
Rationale: The = operator returns true when the linked reference is shared by both objects, which denotes a relational link between them.

^ 3.2. Constants and Enums

v 3.4. Functions