Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can implicit value be also a lazy value when used as implicit method parameter value?

Tags:

scala

I have a test suite which uses Slick for DB access. Some tests in this suite access the DB and some not. My suite has

implicit val db = DB.getDB

which effectively initializes DataBaseDef at the beginning of the suite execution. This value then is used as implicit parameter value for some methods. Also it has the afterAll() which closes the db at the end of suite execution:

override def afterAll():Unit={
    db.close()
    super.afterAll()
  }

Now if I changed to: implicit lazy val db = DB.getDB then what exactly will happen?

If I run only a test which does not use the DB then the connection will not be initialized and in the afterAll() it will still try to close the connection and I have a problem in this case, right? I tried to run but no error happened and no exception was thrown...

My knowledge of implicits is not enough to help me understand it in combination with lazy.

like image 257
Alexander Arendar Avatar asked Jan 04 '23 23:01

Alexander Arendar


2 Answers

then what exactly will happen?

The value won't be initialized until the first access to it.

it will still try to close the connection and I have a problem in this case, right?

When you access db.close(), it will first initialize the value, which means it will call DB.getDb prior to closing the connection. This means, although you didn't intend to, the connection would be still initialized and then immediately closed, hence why you don't see an exception.

like image 164
Yuval Itzchakov Avatar answered Jan 06 '23 12:01

Yuval Itzchakov


To add to the accepted answer, I'd like to point out that implicit are resolved at compile time, while val lazy val and def have implications at runtime only.

If you define an identifier as implicit, it will tell the compiler that you have access to an implicit value of the given type, so any method that need such an implicit parameter will use it; conversely, if you don't declare an implicit identifier of a given type, any call to a method needing a value of that type will throw a compiler error. However, once the code is compiled, there is no need for implicits anymore (they have been replaced by explicit references to the relevant identifier, depending on scope).

Now, at runtime, when an implicit identifier is called, it will be instantiated with the standard rules, so it can be either instantiated and memoized at definition if it's a val, instantiated and memoized at usage if it's a lazy val or instantiated at each usage if it's a def. The fact that it used to be an implicit parameter has no influence on the instantiation rules.

like image 41
Cyrille Corpet Avatar answered Jan 06 '23 11:01

Cyrille Corpet