Last Updated on 16/11/2020
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 level | Access modifier |
Object-private | private[this] |
Private | private |
Protected | protected |
Package-specific | private[your.package] |
Public | no 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!