Classes and objects
A class such as Dog is only a blueprint. To get an actual dog that a program can use, you create an instance of the class, also called an object. Each object is a separate value in memory, made from the same blueprint.
Creating an object
In Scala 3, you create an object by calling the class name like a function:
val rex = Dog()
What the line does:
Dog()runs the class's constructor and returns a brand-newDogobject.val rexdeclares a name that refers to that object. The type,Dog, is worked out from the right-hand side.- The
=connects the two, sorexnow refers to the new dog.
The older form, val rex = new Dog(), is also valid in Scala 3 and creates the same kind of object. The new keyword is optional for classes. The lesson uses the shorter form, which is what you'll see in most current Scala code.
Note that Scala puts the name first and the type, if you write it, after a colon: val rex: Dog = Dog(). The form Dog rex = new Dog(), with the type before the name, is not Scala and doesn't compile.
Many objects from one class
Each call creates a different object, however many times you make it:
val rex = Dog()
val buddy = Dog()
val luna = Dog()
All three variables hold a Dog, but they refer to three independent objects. Changing the data inside one doesn't change the others. They share the blueprint, not the contents.
The difference between the object and the variable that refers to it matters when you copy a variable:
val same = rex
println(rex eq same) // true: one object, two names
println(rex eq luna) // false: two different objects
The first println prints true and the second prints false. The operator eq asks whether two names refer to exactly the same object. Assigning rex to same copies the reference, not the dog.
The ordinary == operator, used on two Dog objects of a class with an empty body, gives the same answers, since the class doesn't define when two of its objects are equal. Later classes can define their own equality.
val and var
A val cannot be pointed at a different object later. var can:
var current = Dog()
val first = current
current = Dog()
println(first eq current) // false: current now refers to a new dog
This prints false. The first dog still exists and is still referred to by first. Use val by default, and var only when a name really needs to be reassigned.
The exercise
The Dog class is already defined in the lesson. Inside mainFunction, create three dogs named rex, buddy and luna. The code after them checks that each name holds an object:
class Dog {
}
class Solution {
def mainFunction(): Unit = {
val rex = Dog()
val buddy = Dog()
val luna = Dog()
if (rex != null) println("rex exists")
if (buddy != null) println("buddy exists")
if (luna != null) println("luna exists")
}
}
Each of the three comparisons is true, so the output is:
rex exists
buddy exists
luna exists
If you leave the declarations out, the code doesn't compile, because the names rex, buddy and luna are not defined. In ordinary Scala code a freshly constructed object is never null, so the checks always pass here. They mostly confirm that the variables exist.
Key takeaways
- A class is the blueprint, and an object is an instance made from it.
- In Scala 3,
Dog()creates an object, andnew Dog()does the same thing. - Every call creates a separate object, and a variable holds a reference to one.
eqtells whether two names refer to the same object.
