Yaroslav
Yaroslav

Reputation: 4659

Apply and lambdas in Scala

I have the following piece of code

scala> val builder = new StringBuilder("foo bar baz ")
builder: StringBuilder = foo bar baz

scala> (0 until 5) foreach { builder.append("!") }

scala> builder.toString
res15: String = foo bar baz !

I guess that in reality something like

(0 until 5) foreach builder.append("!").apply

happens. Can anyone explain to me why that happens or if I'm wrong what really happens?

Upvotes: 3

Views: 207

Answers (2)

Aivean
Aivean

Reputation: 10882

To understand what's happening I used my small tool scala-to-java.

Your code transpiled to Java looks like this:

public final class _$$anon$1 {
  private final StringBuilder builder = new StringBuilder("foo bar baz ");

  private StringBuilder builder() {
    return this.builder;
  }

  {
    RichInt$.MODULE$.until$extension0(Predef$.MODULE$.intWrapper(0), 5).foreach((Function1<Object, Object>)this.builder().append("!"));
    this.builder().toString();
  }
}

As you can see, result of the builder.append("!"), which is also StringBuilder is simply cast to Function1 and used as a function argument in foreach.

Apparently, StringBuilder is indeed a function, if you check it's type hierarchy:

  • StringBuilder (scala.collection.mutable)
  • AbstractSeq (scala.collection.mutable)
  • AbstractSeq (scala.collection)
  • Seq (scala.collection)
  • PartialFunction (scala)
  • Function1 (scala)

As a conclusion:

  • You can use any StringBuilder as an function or partial function from Int to Char
  • In your case, append is evaluated only once and it's result (StringBuilder) is used as a function.

Upvotes: 7

Sascha Kolberg
Sascha Kolberg

Reputation: 7152

foreach expects a function from (in your case) Int => Unit you provide () => StringBuilder. However, as StringBuilder is a collection, it's 'apply' function to retrieve a the Character at a specific index is selected as the function to apply in the foreach loop.

You can fix your code with:

(0 until 5) foreach { _ => builder.append("!")}

Upvotes: 2

Related Questions