Lazy vals and implicit parameters in Scala

I am trying to understand how implicit parameters work in Scala. As far as I can tell about the implicit resolution of the parameters, something like this happens:

  • Explicitly pass the object to the method.
  • implicit definitions defined in an area.
  • Companion object of the class used as an implicit parameter

However, when I started playing with this along with lazy felts, I got a little confidence. It seems that lazy dollars use only the latest permission rules. Here is an example code to illustrate:

class Bar(val name:String)
object Bar { implicit def bar = new Bar("some default bar") }

class Foo {
  lazy val list = initialize
  def initialize(implicit f:Bar) = {
    println("initialize called with Bar: '" + f.name + "' ...")
    List[Int]()
  }
}

trait NonDefaultBar extends Foo {
  implicit def f = new Bar("mixed in implicit bar")
  def mixedInInit = initialize
  lazy val mixedInList = list
}

object Test {
    def test = {
      println("Case 1: with implicitp parameter from companion object")
      val foo1 = new Foo
      foo1.list
      foo1.initialize

      println("Case 2: with mixedin implicit parameter overriding the default one...")
      val foo2 = new Foo with NonDefaultBar 
      foo2.mixedInList

      val foo3 = new Foo with NonDefaultBar 
      foo3.mixedInInit

      println("Case 3: with local implicit parameter overriding the default one...")
      implicit def nonDefaultBar = new Bar("locally scoped implicit bar")
      val foo4 = new Foo 
      foo4.list
      foo4.initialize
    }
}

The call Test.testgives the following output:

Case 1: with implicitp parameter from companion object 
initialize called with Bar: 'some default bar' ... 
initialize called with Bar: 'some default bar' ... 
Case 2: with mixedin implicit parameter overriding the default one... 
initialize called with Bar: 'some default bar' ... 
initialize called with Bar: 'mixed in implicit bar'... 
Case 3: with local implicit parameter overriding the default one... 
initialize called with Bar: 'some default bar' ... 
initialize called with Bar: 'locally scoped implicit bar' ...

Why does the compiler not realize that there is a mixed implict bar when calling mixedInList in case 2. In case 3, it also skips the locally defined implicit bar when accessing the list.

vals, , ?

+5
2

, implicit Bar, Foo. Java :

public class Foo
  implements ScalaObject
{
  private List<Object> list;
  public volatile int bitmap$0;

  public List<Object> list()
  {
    if (
      (this.bitmap$0 & 0x1) == 0);
    synchronized (this)
    {
      if (
        (this.bitmap$0 & 0x1) == 0) {
        this.list = initialize(Bar..MODULE$.bar()); this.bitmap$0 |= 1; } return this.list;
    }
  }
  public List<Object> initialize(Bar f) { Predef..MODULE$.println(new StringBuilder().append("initialize called with Bar: '").append(f.name()).append("' ...").toString());
    return Nil..MODULE$;
  }
}

lazy val - , , , , , . . , .

+4

scala , , . , :

lazy val list = initialize

private var _list: Option[List[Int]] = None
def list(implicit f: Bar) = 
  _list.getOrElse{
    _list = Some(initialize)
    _list.get
  }

Test.test :

Case 1: with implicitp parameter from companion object
initialize called with Bar: 'some default bar' ...
initialize called with Bar: 'some default bar' ...
Case 2: with mixedin implicit parameter overriding the default one...
initialize called with Bar: 'mixed in implicit bar' ...
initialize called with Bar: 'mixed in implicit bar' ...
Case 3: with local implicit parameter overriding the default one...
initialize called with Bar: 'locally scoped implicit bar' ...
initialize called with Bar: 'locally scoped implicit bar' ...

, , val , .

private val _list: MutableOpt[List[Int]] = MutableOpt.from(None)
def list(implicit f: Bar) = _list.getOrSet(initialize)

, scala , :

lazy val list(implicit f: Bar) = initialize

: , , , .

0

All Articles