Methods in Scala
You may be wondering why the section on functions in Java and Scala occasionally uses the word "method" instead of "function."
A method is a special kind of function in object-oriented programming that is definined
in the context of a class of objects.
In a method call such as a.m(b, c), the receiver of the method call—that is,
the object before the dot, a—
is used to select which implementation of the method to use.
Different classes of objects may implement methods in different ways, and the sender
of the method call relies on the object to know the correct implementation (that is, the
decision is object-oriented).
The method call a.m(b, c) effectively turns into a call to the function f(a, b, c),
where f is the implementation of method m suitable for object a.
The receiver a is passed in as an extra argument
to f and is typically accessed through a special keyword such as this or self.
Here is an example in Scala of defining two classes of shapes, Circle and Square, which each define a method area (with no parameters). To express that they both implement this method, we also define a trait (similar to a Java interface) that declares this fact:
trait Shape:
def area: Double
class Circle(val radius: Double) extends Shape:
def area: Double = math.Pi * radius * radius
class Square(val side: Double) extends Shape:
def area: Double = side * side
val s = Circle(1.0)
// s: Circle = repl.MdocSession$MdocApp$Circle@53fef978
println(s.area)
// 3.141592653589793
When we call s.area, the compiler generates code to look up the area method in the class
of s (which will be Circle in this example), and then call that method with s passed in
as the this object.
The Circle version of area takes that hidden this object and uses it to look up the
field radius of object s when it is computing the expression math.Pi * radius * radius.
Operators as Methods
An interesting fact about Scala is that the operators, such as +, *, and ==,
are actually methods of their left-hand operand. That is, x + y is equivalent to
x.+(y), and a compound expression such as a + b * c becomes a.+(b.*(c)) (note
that this takes into account the usual higher precedence of multiplication over addition).
In Scala, it is possible to define new methods (including operators) on existing types,
such as Int, through extension methods.
For example, if we wanted to define an exponentiation operator on Int, and
call it ***, we could define it as follows:1
extension (n: Int)
def ***(p: Int): Int = {
if p == 0 then
1
else if p % 2 == 0 then
(n * n) *** (p / 2)
else
n * (n *** (p - 1))
}
println(2 *** 3)
// 8
(The first line identifies this method as a new implementation to be used when the
receiver of the ***(p) method is an Int; the receiver is given the explicit name n.)