Access Modifiers: Scala & Java

In this post we will analyse the differences and the similarities between access modifiers in Scala and Java. Despite Scala is compatible with Java, there are some differences.

Java

In Java there are four types of access modifiers:

  • public: this is the less restrictive access modifier. Classes, methods, inner classes and fields can be declared public. Every class in every package can access the element declared public.
  • protected: methods, inner classes and fields can be declared protected. Only subclasses or classes in the same package can access the element declared protected.
  • default: classes, methods, inner classes and fields can be declared with no access modifier. Only classes in the same package can access the element declared with no modifier.
  • private: this is the most restrictive modifier. Methods, inner classes and fields can be declared private. Only the own class can access the elements declared private. Private methods or fields existing in an inner class can be accessed by the outer class.

Let’s make it more visual:

Modifier Class Package Subclass Every class
public Y Y Y Y
protected Y Y Y N
default Y Y N N
private Y N N N

Scala

In Scala there are three types of access modifiers (default that behaves like public, protected and private) but they can be augmented with qualifiers (only protected and private can). This qualification means that access is protected or private up to a scope.

First we will explain the unqualified access modifiers:

  • default: this is the less restrictive one, it behaves like public in Java. Classes, methods, inner classes and fields can be declared with no modifier. Every class in every package can access the element declared with no modifier.
  • protected: a member declared protected can be accessed only by its subclasses. This access modifier is more restrictive than its analogous in Java.
  • private: this is the most restrictive modifier. A member declared private can be accessed only by the owner class. This also applies for inner classes. In other words a private member is visible inside the own class and inside any deeper inner class. This rule only applies downwards, so a private member defined in an inner class can not be accessed by any outer class (this is possible in Java).

Let’s see the table:

Modifier Class Package Subclass Every class
default Y Y Y Y
protected Y N Y N
private Y N N N

Right now you could be wondering how to make a member visible for any class in the same package. The answer is scoped access modifiers. As we said, private and protected access modifiers can be qualified with a name of a package or class (scope). Generally scoped private and scoped protected access modifiers behave the same way, except under inheritance when declared on class members. The scope is defined between square brackets.

When the scope of protected or private is a package, the visibility is similar to package visibility in Java (default). Given a class X defined inside the package a.b.c, a member defined with protected[a] (or private[a]) is visible within package a. If you want the same behaviour than default visibility in Java, you must specify protected[c] (or private[c]).

When the scope is a class, the visibility is similar to private with some considerations. Given a class X with an inner class Y, a member in Y defined as protected[X] (or private[X]) behaves identically to private in Java. Otherwise, when defined as protected[Y] (or private[Y]) behaves identically to private in Scala.

There is yet another scope, this, that gives the most restrictive access modifier that exists. When a member of a class is defined as protected[this] (or private[this]), it is illegal to access this member outside the object. In other words, given private[this] var foo = 3, foo only can be accessed this way: this.foo.

Previously we said that scoped protected and private behave identically except under inheritance. The only difference is that scoped protected is less restrictive because, independently of the scope stated, a member defined with protected[something] is visible for any subclass, while when defined with private[something] is not.