Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the eta expansion in Scala?

I am new to Scala. I just heard the term "eta expansion" and roughly know that it means to expand a method to a function object. But I find few resources in SO that systematically introduce it.

I am curious about how eta expansion works in Scala. What are the scenarios that eta expansion are needed? And how eta expansion is implemented in Scala?

I roughly know that in cases like this:

def someMethod(x: Int): Int = x * x

someMethod _ will roughly be translated to a new function object like this:

new Function1[Int, Int] {
  def apply(x: Int): Int = x * x
}

Is it all that Scala does?

like image 896
Lifu Huang Avatar asked Sep 12 '16 07:09

Lifu Huang


2 Answers

The definition, and some examples, are given in http://scala-lang.org/files/archive/spec/2.11/06-expressions.html#method-values.

someMethod _ will roughly be translated to a new function object like this:

Not quite: it's actually

new Function1[Int, Int] {
  def apply(x: Int): Int = someMethod(x)
}

The difference matters e.g. if someMethod is overridden somewhere.

Is it all that Scala does?

You also need to take into account what happens if the method takes multiple parameter lists (you get a function which returns a function) or by-name parameters.

What are the scenarios that eta expansion are needed?

  1. When you specifically ask for it (e.g. someMethod _).

  2. When you use a method (with parameters) where a value of a function type (or a SAM type in Scala 2.12) is expected. E.g.

    def foo(f: Int => Int) = ???
    
    foo(someMethod)
    
  3. That's it.

Note that using eta-expansion and an anonymous function with placeholders (someMethod(_)) can behave differently due to type inference, implicits, etc.

like image 152
Alexey Romanov Avatar answered Oct 12 '22 18:10

Alexey Romanov


Eta expansion In high level, is a process of translating methods into functions. Why? What? Aren't them the same? Let's explain:

A method in scala is what we know as def someMethodName(SomePramList): SomeReturnType. It starts with def. It may have parameter list, or even maybe more then 1. For example:

def numAdder(num1: Int)(num2: Int): Int = 
    num1 + num2

A function, or lambda function looks something like: (SomeParams) => SomeReturnType. For example:

val aFunction: Int => Int => Int = (num1: Int) => (num2: Int) => num1 + num2

Important to understand about functions is that this syntax is basically a syntactic sugar to FunctionN.apply method.

What are the scenarios that eta expansion are needed?

Some examples:

Example1 - Applying a method inside map (or filter, flatMap etc)

Writing such code:

def addPlus1(x: Int): Int = x + 1
List(1,2,3).map(addPlus1)

The compiler needs to have a function inside the map. So, it transforms the method given into a function: List(1,2,3).map(x => addPlus1(x)). This is Eta expansion.

Example2 - currying

When defining curried method, for example:

def numAdder(num1: Int)(num2: Int): Int = 
    num1 + num2

And them creating a function like:

val curriedFunction: Int => Int = numAdder(4)
//or
val curriedFunction2 = numAdder(4) _

We defined a function out of a method. This is Eta expansion.

Some more examples

Defined a method which accepts a function value:

def someMethod(f: () => Int): Int = f()
def method(): Int = 10

And then run:

someMethod(method)

will transform the method method into a function. This is Eta expansion

like image 22
Aaron_ab Avatar answered Oct 12 '22 17:10

Aaron_ab