Keep control: Modifiers, kinds of references and objects
(1/5)Kinds of objects
In object oriented languages, objects can form complex networks of dependencies by referring to each other using their fields. The Reachable Object Graph (ROG) of a given object is the set of all objects reachable from it, including itself.
An object is mutated if a field of an object in its ROG is updated .
A
Let's now define a mutable
-
The
« » field is« » . This is called avariable field : a field that can be updated by calling a setter. Non-variable fields can not be updated. -
« » is a« » .
We have seen a« » already, and we have seen methods such as« » and« » showing no modifier; they implicitly have the default modifier« » . Similarly, whenever a type does not specify a modifier, it has the default modifier« » .
« » methods can mutate the« » object. If you have experience with C++ you can see the contrast with const methods. Immutable (default) methods works only on immutable« » objects. Later, we will see much more about modifiers.
As you see, we are using the
We can use
(2/5)Interaction between mutable and immutable
We now explore some interaction between mutable and immutable objects.
Here we use
The method
The method then uses the
In general, methods starting with # should be used with care.
This code models an animal following a path. It can be used like this:
In this code the first dog goes to 12: 20. The second dog goes to 0: 0. This code involves a mutable animal with a mutable field. This is often a terrible idea, since its behaviour may depend on aliasing: what happens if two dogs follow the same path? The first dog moves and consumes the path for the second one as well. That is, the first goes to 12: 20 and the second goes to 1: 2. This is because(3/5)Capsules: Keep aliasing graphs untangled
In 42 we can change
A mutable object with encapsulated state can only be mutated by calling one of its methods. This allows for the same kind of local reasoning as if all of the fields were immutable.
A capsule mutator is a class method whose first parameter is the capsule field as
The annotation is called
Note that we cannot have
(4/5)Handle mutability
Immutable objects of any class
How can we get an immutable
immutable dog1.move() //dog2.move() //ill-typed, requires a mut Animal ]]>We will not explain in this tutorial the exact rules for promotion, but the main idea is that if the initialization expression uses local bindings in a controlled/safe way, then promotion can be applied. For example, a mutable expression using only capsule or immutable references can be promoted to capsule or immutable, as we prefer.
lent and read
We have seen immutable, mutable, capsule and class.
The are still two modifiers:
A method with a single mut parameter can still be called using a lent reference in place of it.
(5/5) Summary
Kinds of classes, summary
- immutable classes: have only immutable fields. It is useful to model mathematical concepts. It is easy to reason about code using immutable classes, but some properties of real objects can be better modelled with state mutation.
- shallow mutable classes: have only (variable) fields of immutable or capsule type (or class, as we will see later). Reasoning with shallow mutable classes is near as easy as reasoning with immutable ones, and often more natural.
- deep mutable classes: have mutable fields. Reasoning with deep mutable classes can be very hard.
Modifiers: summary
- immutable: the default. When you omit the modifier, you mean immutable. An immutable reference points to an object that is never changing. Its whole reachable object graph never changes and is immutable as well.
- mutable: A mutable reference behaves like a normal reference in Java, C#, C++ , Python and many other languages. Mutable references require mutable objects and allow mutating the referred object.
- capsule: capsule references are used only once and they guarantee that the whole reachable object graph is reachable only through that capsule reference. Capsule references provide a structured way to reason over deep mutable objects. Fields can be annotated capsule, the meaning is that they need to be initialized/updated with capsule variables. We will discuss more about capsule fields and how they differ from capsule references later.
- read: A readable reference can not be used to mutate the referred object; but other mutable references pointing to the same object can mutate it. Read references can point to both mutable and immutable objects. It is easy to be confused between read and immutable references. As a rule of thumb, if you are in doubt about whether to use an immutable or a readable reference, you probably want an immutable reference.
- lent: a hygienic mutable reference allowing mutation but not storage. Lent and read are useful to handle in controlled way the state of deep mutable classes; moreover using lent and read on method parameters allows to make explicit what are the method intentions and requirements.
- class: class references denote the class object, on methods the meaning is the same of static methods in many languages, but it can consistently be used on parameters/local variables/fields to encode behaviours similar to dependency injection.
Keep control, summary
- mutable: mutable objects can be freely aliased and mutated. They allow for a liberal programming style like we can find in Java/C++/C# or Python. They can be referred to by capsule, mutable, lent and read references.
- immutable: immutable objects can be obtained by promoting instances of mutable classes. They can be referred to only by immutable and read references.
- class: class objects can be accessed from anywhere by using the corresponding class name; It is also possible to store them into (class) local binding. Some programmers found the fact that class objects are instances of themselves deeply concerning or disturbing, while for others it is just a good story to tell to break the ice at parties.