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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With