In Scala we can define functions/methods inside other functions/methods in same class, and those functions are locally scoped to the functions/methods they are defined to, unable to access outside of from the function they are defined inside. Would that make those locally defined functions private access specifier in Scala?
-
Related: https://stackoverflow.com/questions/59428409/how-are-nested-functions-and-lexical-scope-compiled-in-jvm-languages – user Jun 05 '20 at 19:00
-
Specifiers apply to "members of classes, objects, traits and packages". A locally defined function is none of those, so it has no specifier https://en.wikibooks.org/wiki/Scala/Access_modifiers – pidge Jun 05 '20 at 19:40
3 Answers
Those functions are basically local variables, and as such don't have access modifiers. There's no real need to give them modifiers since the method inside which they are defined is the only place where they can be accessed, and they're only used in a very small part of your application. I suppose they are private by default, if you take private to mean that they can only be accessed in the lowest scope they are in.
As @Luis Miguel Mejía Suárez and @Mario Galic pointed out, these local/nested functions get turned into private (final) methods in the same class. So in a way, yes, they are private
(to the class they are in, not the enclosing method), but you cannot actually access them from other methods in the same class without using reflection or something else.

- 7,435
- 3
- 14
- 44
-
2As a interesting side note, On the JVM they are implemented as private methods in the class. But yeah, from a language point of view, they are just inner functions, nothing more, nothing less. – Luis Miguel Mejía Suárez Jun 05 '20 at 18:06
-
Executing scalac -Xshow-phases
outputs compiler phases and the following seems interesting
lambdalift 17 move nested functions to top level
For example, running scalac -Xprint:lambdalift
on
class O {
def f() = {
def nested() = 42
nested()
}
}
outputs on my machine with Scala 2.13.2 something like
class O {
def f(): Int = nested();
private def nested(): Int = 42;
}
where we see nested method became private member method of the enclosing class. You could try exploring what happens for inner functions using the same technique.

- 47,285
- 6
- 56
- 98
-
4Is that actually guaranteed by the Scala Language Specification and true for every implementation that exists, has ever existed, and will ever exist? Or is it an incidental private internal implementation detail of one specific version of one specific implementation? – Jörg W Mittag Jun 05 '20 at 17:35
On language level according to Scala specification there are only the following access modifiers
https://scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#modifiers
<no modifier>
private
private[C]
private[this]
protected
protected[C]
protected[this]
So on language level the answer for your question is that there is no access modifier specific for nested methods.
On implementation level there are plenty of modifiers and flags (some of them are access modifiers)
https://github.com/scala/scala/blob/2.13.x/src/reflect/scala/reflect/internal/Flags.scala
PROTECTED
PRIVATE
LOCAL
SEALED
METHOD
...
We can peep on compiler if we create an annotation
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
@compileTimeOnly("enable macro paradise")
class printMethodModifiers extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro PrintMethodModifiersMacro.impl
}
object PrintMethodModifiersMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
val traverser = new Traverser {
override def traverse(tree: Tree): Unit = {
tree match {
case q"${mods: Modifiers} def $_[..$_](...$_): $_ = $_" =>
println(s"tree=$tree, mods.flags=${mods.flags}")
case _ => ()
}
super.traverse(tree)
}
}
traverser.traverse(annottees.head)
q"..$annottees"
}
}
and use it to traverse the tree of class
@printMethodModifiers
class O {
def f() = {
def nested() = 42
nested()
}
}
//Warning:scalac: tree=def <init>() = {
// super.<init>();
// ()
//}, mods.flags=0
//Warning:scalac: tree=def f() = {
// def nested() = 42;
// nested()
//}, mods.flags=0
//Warning:scalac: tree=def nested() = 42, mods.flags=0
So when macro annotations are expanded in typer
phase there is no difference in flags for methods and nested methods.

- 48,194
- 3
- 28
- 66