Implicit keyword implicit - keyword means that compiler should try to use function or variable even if it's not explicitly specified in code.
implicit variables and functions are:
How to add implicit conversion Let say we want to add special debug method to every object in code. That method should return toString of object followed by length of this string.
trait HasDebugString {
def toDebugString =
this.toString + " " + this.toString.length
}
class X extends HasDebugString
but it's impossible when we use third party code
class XDebug extends X with HasDebugStringBut we don't want to do this for each class in project, right?
case class X(text : String)
class DebugStringWrapper(instance : X) {
def toDebugString =
instance.toString + instance.toString.length
}
def wrap(instance : X) = new DebugStringWrapper(instance);
wrap(new X("ABC")).toDebugString
//X(ABC)6 (result)
//written only once
class DebugStringWrapper[T](instance : T) {
def toDebugString =
instance.toString + instance.toString.length
}
def wrap[T](instance : T) = new DebugStringWrapper(instance);
Other parts of code can use wrapper
case class X(text : String)
wrap(new X("ABC")).toDebugString //X(ABC)6 (result)
wrap(new X("ABC")).toDebugString //X(ABC)6 (result)
wrap(6).toDebugString //61 (result)
wrap("ABC").toDebugString //ABC3 (result)
wrap(List(1,2)).toDebugString //List(1, 2)10 (result)
wrap(6).toDebugString == 6.toDebugStringActually we can... implicit magic...
implicit def hiddenwrap[T](instance : T) = new DebugStringWrapper(instance);
wrap(List(1,2)).toDebugString //List(1, 2)10 (result)
hiddenwrap(List(1,2)).toDebugString //List(1, 2)10 (result)
List(1,2).toDebugString //List(1, 2)10 (result)
implicit def hiddenwrap[T](instance : T) = new {
def toDebugString = instance.toString + instance.toString.length
}
List(1,2,3).toDebugString //List(1, 2, 3)13 (result)
How to add operator to existing class In Scala operators are just methods
Postfix operators are bound to left of operand. They're easy to implement
implicit def opwrap[T](instance : T) = new {
def ! = instance.toString + instance.toString.length
}
List(1,2,3).! //List(1, 2, 3)13 (result)The difference is that you can skip a dot
List(1,2,3)! //List(1, 2, 3)13 (result)
How to add prefix operator to existing class Prefix operator method name has to start with "unary_"
implicit def opwrap2[T](instance : List[T]) = new {
def unary_! = instance.isEmpty
}
println(!List(1,2,3)) //() false(result)
println(!Nil) //() true(result)
println(List(1,2,3).!) //() List(1, 2, 3)13(result)
How to add infix operator to existing class Infix operators take two operands one from left and one from right.
Here operator (!) takes two lists with elements of type TR and TL and returns smaller of them
implicit def opwrap3[TL](instance : List[TL]) = new {
def  =
if (instance.length > other.length) instance else other
}
List(1,2,3) ! List("A","B") //List(1, 2, 3) (result)
List(1,2,3).!(List("A","B")) //List(1, 2, 3) (result)
opwrap3(List(1,2,3)).!(List("A","B")) //List(1, 2, 3) (result)
Infix operator names with colons If infix operator name ends with colon (":") then operator is bound to right term
implicit def opwrap4[TL](instance : List[TL]) = new {
def !:[TR](other : List[TR]) =
instance + ".!:(" + other + ")"
}
List(1,2,3) !: List("A","B") //List(A, B).!:(List(1, 2, 3)) (result)
List("A","B").!:(List(1,2,3)) //List(A, B).!:(List(1, 2, 3)) (result)
opwrap4(List("A","B")).!:(List(1,2,3)) //List(A, B).!:(List(1, 2, 3)) (result)
Common errors
List(1,2,3).toDebugString
found : List[Int]
required: ?{def toDebugString: ?}
Note that implicit conversions are not applicable
because they are ambiguous:
both method hiddenwrap2 of type
[T](instance: T)AnyRef{def toDebugString: String}
and method hiddenwrap of type
[T](instance: T)DebugStringWrapper[T]
are possible conversion functions
from List[Int]to ?{def toDebugString: ?}
You cannot use implicit methods to override existing methods. Implicit method is applied only if method does not exists in class
implicit def happystring[T](instance : T) = new {
override def toString = instance.toString + ":)"
def withSmiley = instance.toString + ":)"
}
//BAD: X has toString method
println(X("I'm sad").toString) //() X(I'm sad)(result)
//GOOD: toString is not found in X, so implicit conversion will be applied
println(X("I'm happy").withSmiley) //() X(I'm happy):)(result)
No comments:
Post a Comment