Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why I cant add field to scala implicit class?

Tags:

scala

Why you can not add a field to the implicit class?

for example the below code does not store the originalName field

object Implicit1 {

  implicit class AI1(c: Class[_]) {
    private var originalName = ""

    def setOriginalName(str: String) = originalName = str

    def getOriginalName=originalName
  }
}
like image 512
Pooya Avatar asked Oct 20 '25 01:10

Pooya


2 Answers

An implicit class is a class that can be implicitly invoked as a wrapper for your class (in this case an instance of Class). It absolutely can have a var; your code works fine in that sense.

The problem is that you have no way to get an instance of AI1. So you create it, load up the var, and then throw it away. It's not part of the original c: Class[_] instance; there's no monkey-patching going on here. It just saves you typing (new AI1(c)).whicheverMethodYouPutOnAI1.

And if you did have a way to get an AI1, you wouldn't be able to get c again as you've written it. AI1 is not a proxy for Class[_], it just holds an instance of it. And right now your getter and setter don't add anything over just exposing the var. So you perhaps meant something like

implicit class AI1(val underlying: Class[_]) {
  var originalName = ""
  def hasName = this
}

Now you can do things like

val named = "fish".getClass.hasName
named.originalName = "salmon"
println(s"${named.originalName} ${named.underlying}")
like image 169
Rex Kerr Avatar answered Oct 21 '25 20:10

Rex Kerr


As Rex Kerr mentioned, the implicit class will be created every time when need. Hence you will get a new instance of the implicit class every time, the value stored in the field has lost.

scala> val clz = "str".getClass
clz: Class[_ <: String] = class java.lang.String

scala> val impA: AT1 = clz
impA: Imp.AT1 = Imp$AT1@2d96543c

scala> val impB: AT1 = clz
impB: Imp.AT1 = Imp$AT1@7a560583

scala> impA == impB
res2: Boolean = false

Here is a workaround:

scala> :paste
// Entering paste mode (ctrl-D to finish)

object Imp {
   object AT1 {
     val clzBuffer = collection.mutable.Buffer[Class[_]]()
     val strBuffer = collection.mutable.Buffer[String]()
     def setName(clz: Class[_], name: String): Unit = {
       val ind = clzBuffer indexWhere (_ eq clz)
       if(ind == -1) {
         clzBuffer += clz
         strBuffer += name
       }
       else {
         strBuffer(ind) = name
       }
     }
     def getName(clz: Class[_]): String = {
       val ind = clzBuffer indexWhere (_ eq clz)
       if(ind == -1) "" else strBuffer(ind)
     }
   }

   implicit class AT1(c: Class[_]) {
     def originalName: String = AT1.getName(c)
     def originalName_=(name: String) = AT1.setName(c, name)
   }
} 

// Exiting paste mode, now interpreting.

defined object Imp

scala> import Imp._
import Imp._

scala> val clz = "str".getClass
clz: Class[_ <: String] = class java.lang.String

scala> clz.originalName
res0: String = ""

scala> clz.originalName = "IamHere"
clz.originalName: String = IamHere

scala> clz.originalName
res1: String = IamHere
like image 31
Eastsun Avatar answered Oct 21 '25 20:10

Eastsun



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!