← Back to list

In Scala, a value can override a function

Sometimes, you learn something about a programming language, then forget it, then don’t remember it again until you come across a situation…

Alonso Del Arte · 2026-05-21 21:46 · 0 claps · 5.3 min read
#software-development #uniform-access-principle #java #scala
Open on Medium ↗
Wiki topics: 💻 · Programming

In Scala, a value can override a function

Photo by Khara Woods on Unsplash

Photo by Khara Woods on Unsplash

Sometimes, you learn something about a programming language, then forget it, then don’t remember it again until you come across a situation in which you need that concept. Such a thing happened to me with the uniform access principle in Scala.

The uniform access principle is by no means unique to Scala. It’s a concept that was first formulated by Bertrand Meyer in the 1980s and deployed in his programming language Eiffel, which came out at about the same time. Java 1.0 came out in 1996, and Scala 1.0 came out in 2003.

Meyer wrote in his book, Object-Oriented Software Construction, that

All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation.

This quotation of Meyer is universally regarded as the definition of the uniform access principle. This definition suggests that abiding or not abiding by the principle is up to individual programmers, though the choice of programming language can help or hinder.

Encapsulating implementation details, such as whether a service is implemented through storage or through computation, simplifies refactoring. If it’s more efficient to change storage to computation, or the other way around, we can do so without breaking modules that depend on that particular service.

Keep in mind that back in the 1980s, refactoring could be difficult at times. If storage retrieval and computation use different notations, changing one to the other might mean changes to several different files.

Even now, with our integrated development environments (IDEs) like Apache NetBeans and IntelliJ IDEA for Java, having to add in or remove empty parentheses can be time-consuming.

Java is not inclined to observing the uniform access principle, but Scala is, and Scala can help in the observance of this principle, even when importing from the Java Development Kit (JDK).

Suppose point is an instance of java.awt.Point. Then point.x accesses the stored property x of the point (x, y), whereas point.getX() performs a computation, though it is a relatively simple computation.

With Java it’s very clear that no parentheses definitely means retrieval from storage. Parentheses imply a computation, but could just as easily also be retrieval from storage.

If you want to observe the uniform access principle in your own Java projects, that would mean that you avoid exposing fields outside of a class, making the getters and setters the only way to access those fields by instances of other classes.

It matters what you name things. In the vast majority of programming languages, you still have to name things, and you can make choices that subvert the uniform access principle.

In his essay on the uniform access principle, software expert Martin Fowler gives the toy example of getting the age of a user from an object holding the user’s personal information. If the class provides an age accessor, it should be named getAge() rather than calcAge().

With getAge(), we can choose to believe that the user information object is retrieving the age from somewhere that is presumably appropriately updated independently of our program.

But calcAge() strongly suggests that each call results in a recalculation of the user’s age by subtracting the user’s date of birth from today’s date.

In a real life use case, we would have to consider if the user information object is supposed to persist in memory for days rather than be created anew each time it’s needed, such as might be the case with object-relational mapping from a database.

In the case of Point, we’re probably not expecting Point objects to persist in memory for days. So naming the x and y accessors calcX() and calcY() might be overkill, even if a small computation does take place.

The declaration of Point goes something along the lines of this sketch:

public class Point {

    // serialVersionUID goes here

    public int x, y;

    public double getX() {
        return (double) this.x;
    }

    public double getY() {
        return (double) this.y;
    }

    // Other functions

    // Procedures

    // Constructors

}

The actual JDK source does not explicitly cast x to double. But that’s what the compiler writes.

The object stores x as a 32-bit signed integer, and getX() converts that 32-bit integer to a 64-bit floating point number. Same thing with y and getY().

It’s a simple computation that the Java Virtual Machine (JVM) can perform very quickly, but it’s not a simple matter of filling in 0s or 1s in the extra bits.

Still, if you write “point.getX()” in your program, do you really care how the JVM obtains x as a floating point number? Probably not.

And in Scala, you don’t have to. In Scala, when a function or procedure does not take any parameters, the compiler often allows you to omit the empty parentheses. The compiler might even warn you if you include parentheses when you don’t have to.

With java.awt.Point imported into a Scala project, and point defined as an instance of Point, you can get x as a floating point number with either point.getX or point.getX(), though the latter triggers the warning “Java accessor method called with empty argument clause” in IntelliJ IDEA. And IntelliJ IDEA also offers to remove the parentheses for you.

If we rewrote java.awt.Point in Scala, we might start with

class Point(var x: Int, var y: Int)

At this early juncture, Scala even allows us to omit the curly braces. We get field access to x and to y, and we might decide that the caller can convert those to Double on their own if it’s really necessary.

While we’re at it, can we rewrite Point as an immutable class? Well, that’s a topic for another article. Immutability does help with the uniform access principle. If a field is truly final, there’s no harm in allowing direct access to it, and no worry that the name of an accessor could betray the implementation.

Scala’s observance of the uniform access principle has a few consequences that I find surprising. I’m going to show you the example from an actual project of mine that reminded me of this concept in the first place.

I’m working on a chess program in Scala. It needs to represent chess pieces. Chess pieces have several characteristics in common, so it makes sense to have one class that can represent any chess piece. I’ve named that class “Piece,” obviously.

But they also have several differences from each other, which makes it necessary to have subclasses of Piece. And Piece should be an abstract class.

abstract class Piece {
  val affiliation: Player
  val possibleMoves: Set[RelativePositionRange]
  val canJumpOver: Boolean = false
  val captureSameAsMove: Boolean = true
  val hasSpecialMoves: Boolean = false

  def possibleCaptures: Set[RelativePositionRange] =
    if (this.captureSameAsMove) this.possibleMoves else Set()

}

Note that possibleCaptures() is a function that depends on the value of the field captureSameAsMove. I’m using the parentheses, which are unnecessary in Scala, to make the point obvious to those of you more familiar with Java.

Most pieces, like rooks, for example, capture the same as they move, so possibleCaptures() can be the same as possibleMoves. So Rook does not need to override possibleCaptures().

But if I needed to override possibleCaptures() for Rook, I could do so in two different ways without getting any errors or warnings. I can write

override val possibleCaptures: Set[RelativePositionRange] = Rook.moves

or

  override def possibleCaptures: Set[RelativePositionRange] = Rook.moves

I can put parentheses on the latter if I really want to, but then I get a warning that the parentheses are redundant.

There is the question of whether you want to abide by the uniform access principle. Detractors point out that some computations are slow or otherwise expensive, so it would be nice to have some indication of that in the name of the accessor.

I have not formulated my own opinion on the matter yet. But you can do worse than adopting Martin Fowler’s opinion that you should mostly abide by the uniform access principle, deviating from it only for accessors that are proven to be slow, not merely believed to be slow.


메타데이터
post_id
a1e3ef78eb7b
slug
in-scala-a-value-can-override-a-function-a1e3ef78eb7b
url
https://medium.com/@alonso-delarte/in-scala-a-value-can-override-a-function-a1e3ef78eb7b
canonical_url
https://medium.com/@alonso-delarte/in-scala-a-value-can-override-a-function-a1e3ef78eb7b
author_url
https://medium.com/@alonso-delarte
status
ok
fetched_at
2026-06-09 15:37:30