Skip to content

Scala: access modifiers

Last Updated on 16/11/2020

Scala access modifiers

Scala provides a more granular access control if compared to Java. This post describes and shows how to implement each of the Scala access modifiers.

Access modifiers

Scala has only two explicit access modifiers: private and protected, besides the implicit no modifier that defaults to public access.

However, we can qualify these modifiers to give them a finer-grained access control level.

Access levels

The access levels from the most-restrictive to the less-restrictive are the following:

Access levelAccess modifier
Object-privateprivate[this]
Privateprivate
Protectedprotected
Package-specificprivate[your.package]
Publicno modifier

Object-private

This is the most restrictive access level, declared by qualifying the member as private[this]. Object-private members can only be called within the same instance:

class Bar {
  private[this] def doSomethingVeryRestrictive(): Unit = {
    println("Object-private method.")
  }

  def callVeryRestrictiveMethod(): Unit = {
    doSomethingVeryRestrictive()
  }

  def cannotCallFromOtherObject(otherBar: Bar): Unit = {
    otherBar.doSomethingVeryRestrictive() // Doesn't compile
  }
}

Private

Declared with the private keyword. Similar to Java, Private members can be called only by the same class:

package com.bgasparotto.learningscala.accessmodifier

class Baz {
  private def doSomethingPrivate(): Unit = {
    println("Private method.")
  }

  def callPrivateMethod(otherBaz: Baz): Unit = {
    otherBaz.doSomethingPrivate()
  }
}

class NotBaz {
  def cannotCallPrivateMethodFromOtherClass(baz: Baz): Unit = {
    baz.doSomethingPrivate() // Doesn't compile
  }
}

Protected

Declared with the protected keyword. Unlike Java, protected members can be accessed only by subclasses, but not from other classes in the same package:

package com.bgasparotto.learningscala.accessmodifier

// Declares a protected method
class Boo {
  protected def doSomethingProtected(): Unit = {
    println("Protected method.")
  }
}
package com.bgasparotto.learningscala.accessmodifier.other

import com.bgasparotto.learningscala.accessmodifier.Boo

// Subclass of Boo (can be either on the same or different package)
class SubBoo extends Boo {
  def callProtectedMethodHere(boo: Boo): Unit = {
    doSomethingProtected()
  }

  def callProtectedMethodThere(boo: Boo): Unit = {
    boo.doSomethingProtected()
  }
}
package com.bgasparotto.learningscala.accessmodifier

// Doesn't work: resides on the same package but it is not a subclass
class NotSubBoo {
  def cannotCallProtectedMethodSamePackage(boo: Boo): Unit = {
    boo.doSomethingProtected() // Doesn't compile
  }
}

Package-specific

Declared using a combination of the keyword private and the package level starting from the current location and optionally stepping-up the hierarchy.

In other words, the package-specific access level defines whether your type will be available only to members of the current package and its sub-packages, or to members of an upper-level package including its sub-packages as well:

package com.bgasparotto.learningscala.accessmodifier.other

class Fuz {
  private[accessmodifier] def doSomethingAbroad(): Unit = {
    println("Package-specific to packages [accessmodifier] and any of its sub-packages.")
  }

  private[other] def doSomethingFromPackage(): Unit = {
    println("Package-private method (specific to [other])")
  }
}

The class Foz from the same package have access to all Fuz methods:

package com.bgasparotto.learningscala.accessmodifier.other

class Foz {
  def callPackagePrivateMethod(fuz: Fuz): Unit = {
    fuz.doSomethingAbroad()
  }

  def callBroaderPackageSpecificMethod(fuz: Fuz): Unit = {
    fuz.doSomethingFromPackage()
  }
}

The class AnotherFuz can access only the method restricted to the accessmodifier package and its sub-packages, which this case is defined in accessmodifier.another:

package com.bgasparotto.learningscala.accessmodifier.another

import com.bgasparotto.learningscala.accessmodifier.other.Fuz

class AnotherFuz {
  def callAccessibleMethod(fuz: Fuz): Unit = {
    fuz.doSomethingAbroad()
  }

  def cannotCallTheOtherOne(fuz: Fuz): Unit = {
    fuz.doSomethingFromPackage() // Doesn't compile
  }
}

And as expected, Faz which resides in an even higher package can’t access any methods:

package com.bgasparotto.learningscala

import com.bgasparotto.learningscala.accessmodifier.other.Fuz

class Faz {
  def callAccessibleMethod(fuz: Fuz): Unit = {
    fuz.doSomethingAbroad() // Doesn't compile
  }

  def cannotCallTheOtherOne(fuz: Fuz): Unit = {
    fuz.doSomethingFromPackage() // Doesn't compile either
  }
}

Public: the default access level

Finally, when no access modifier is declared, the access level is set to public by default.

/* Public class given no access modifier was declared. */
class Foo {
  def doSomething(): Unit = {
    println("Public method.")
  }
}

Unlike in Java, the keyword public is not reserved in Scala.

Hope it helps!

Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *