Hanfei Sun
Hanfei Sun

Reputation: 47051

In Scala, how to define a implicit value/parameter in companion object?

I saw codes below from this Link

abstract class SessionFactory {

  protected[squery] def createConnection(): Connection

  def createSession(): Session = new Session(this)

  def withSession[T](f: Session => T): T = {
    val s = createSession()
    try { f(s) } finally s.close()
  }

  def withSession[T](f: => T): T =
    withSession { s: Session => SessionFactory.dyn.withValue(s)(f) }
}

object SessionFactory {

  private val dyn = new DynamicVariable[Session](null)

  implicit def getThreadSession: Session = {
    val s = dyn.value
    if(s eq null)
      throw new SQLException("No implicit thread session available; getThreadSession() can only be used within a withSession block")
    else s
  }
}

I don't know how could def withSession[T](f: => T): T get the value for s:Session, so I tried to reproduce this usage of implicit in a simple snippet:

class printTest {
  def printWithParameter(s:String) = println(s)
  def printWithImplicit = printWithParameter(s:String)
}

object printTest {
  implicit val sp:String = "implicit value"
  implicit def getString:String = "implicit def"
}

val pt = new printTest()
pt.printWithImplicit

But the printTest doesn't work, the compiler says:

Error:(3, 47) not found: value s
  def printWithImplicit = printWithParameter(s:String)
                                             ^

Does anyone have ideas about this?

Upvotes: 0

Views: 168

Answers (2)

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297195

You have been misled. The implicit is not being used, because that method is not getting a value for Session. Let's review it:

def withSession[T](f: => T): T =
  withSession { s: Session => SessionFactory.dyn.withValue(s)(f) }

So, it takes an f of type T, passed by-name (that is, it is evaluated when used, not when withSession is called). It then calls withSession passing a function from Session to T. It does not create a Session, it asks for a Session, so to speak. So let's see what it called:

def withSession[T](f: Session => T): T = {
  val s = createSession()
  try { f(s) } finally s.close()
}

Here it takes a function from Session to T (which is going to be s: Session => SessionFactory.dyn.withValue(s)(f)), creates a Session, and then use that session to invoke the function that was passed. The session creation is just a new Session(this), so nowhere is there any implicit being used.

Upvotes: 2

user2829759
user2829759

Reputation: 3512

This reason you get

Error:(3, 47) not found: value s
  def printWithImplicit = printWithParameter(s:String)
                                             ^

is because you defined a function called printWithImplicit which takes no parameter and return Unit. It can be explicitly written as: def printWithImplicit(): Unit

Since it takes no parameters, so its function body, in this case, printWithParameter(s:String), find no definition of s

Back to your question.

You need to import printTest.sp before

val pt = new printTest()
pt.printWithImplicit

I stripped your example down a bit:

class printTest {
  def printWithParameter(s:String) = println(s)
  def printWithImplicit(implicit s:String) = printWithParameter(s)
}

object printTest {
  implicit val sp:String = "implicit value"
}

import printTest.sp
val pt = new printTest()
pt.printWithImplicit

Upvotes: 2

Related Questions