Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the access specifier of local functions in Scala?

Tags:

scala

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?

like image 766
bey Avatar asked Jun 05 '20 16:06

bey


People also ask

What does => mean in Scala?

=> is the "function arrow". It is used both in function type signatures as well as anonymous function terms. () => Unit is a shorthand for Function0[Unit] , which is the type of functions which take no arguments and return nothing useful (like void in other languages).

What are the functions in Scala?

In scala, functions are first class values. You can store function value, pass function as an argument and return function as a value from other function. You can create function by using def keyword. You must mention return type of parameters while defining function and return type of a function is optional.

What keywords does the Scala language have to denote access types for methods?

public, private and protected are the three access modifiers used in Scala. Include the keywords private/protected/public in the definition of class, object or package to enforce the corresponding scope. If none of these keywords are used, then the access modifier is public by default.

What do you call a function defined in a block in Scala?

A method is a function defined in a class and available from any instance of the class. The standard way to invoke methods in Scala (as in Java and Ruby) is with infix dot notation, where the method name is prefixed by the name of its instance and the dot ( . )

What are Scala access modifiers?

This chapter takes you through the Scala access modifiers. Members of packages, classes or objects can be labeled with the access modifiers private and protected, and if we are not using either of these two keywords, then access will be assumed as public. These modifiers restrict accesses to the members to certain regions of code.

What is the default access level for public in Scala?

Public: There is no public keyword in Scala. The default access level (when no modifier is specified) corresponds to Java’s public access level.We can access these anywhere. Writing code in comment? Please use ide.geeksforgeeks.org , generate link and share the link here.

How to define a function in Scala?

Function name in Scala can have characters like +, ~, &, –, ++, \, / etc. parameter_list: In Scala, comma-separated list of the input parameters are defined, preceded with their data type, within the enclosed parenthesis. return_type: User must mention return type of parameters while defining function and return type of a function is optional.

How to access a private member in Scala?

A private member is visible only inside the class or object that contains the member definition. In Scala, the access (new Inner). f () is illegal because f is declared private in Inner and the access is not from within class Inner.


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.

like image 192
user Avatar answered Oct 27 '22 00:10

user


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.

like image 38
Mario Galic Avatar answered Oct 27 '22 00:10

Mario Galic


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.

like image 35
Dmytro Mitin Avatar answered Oct 26 '22 22:10

Dmytro Mitin