21
Implicit Conversion and Parameters in Scala Piyush Mishra Software Consultant Knoldus software LLP

Implicit conversion and parameters

Embed Size (px)

Citation preview

Page 1: Implicit conversion and parameters

Implicit Conversion and Parameters in Scala

Piyush MishraSoftware Consultant

Knoldus software LLP

Page 2: Implicit conversion and parameters

Topics Covered

Why Implicit are needed

Implicit conversions

Rule for Implicit

Where Implicit are tried

Implicit Parameters

Debugging Implicit

Page 3: Implicit conversion and parameters

Why Implicit are needed

There’s a fundamental difference between your own code and libraries of other people

you can change or extend your own code as you wish

but if you want to use someone else’s libraries, you usually have to take them as they are.

They are also used in resolving type check errors.

So in order to use others library as yours you use implicit conversions and parameters

Page 4: Implicit conversion and parameters

Implicit ConversionOne of the central collection traits in Scala isRandomAccessSeq[T], which describes random access sequences over ele-ments of type T.

Java’s String class does not inherit from Scala’sRandomAccessSeq trait.

Page 5: Implicit conversion and parameters

Implicit Conversion

In situations like this, implicits can help. To make a String appear to be a subtype of RandomAccessSeq, you can define an implicit conversion from String to an adapter class that actually is a subtype of RandomAccessSeq

implicit def stringWrapper(s: String) =new RandomAccessSeq[Char] {def length = s.lengthdef apply(i: Int) = s.charAt(i)}

scala> stringWrapper("abc123") exists (_.isDigit)res0: Boolean = true

Page 6: Implicit conversion and parameters

Rules For Implicit

Implicit definitions are those that the compiler is allowed to insert into a program in order to fix any of its type errors .

Implicit conversions are governed by the following general rules.

Page 7: Implicit conversion and parameters

Marking Rule

Only definitions marked implicit are available. The implicit keyword is used to mark which declarations the compiler mayuse as implicits. we can use it to mark any variable, function, or objectDefinition.

implicit def intToString(x: Int) = x.toString

The compiler will only change x + y convert(x) + y if convert is marked as implicit. The compiler will only select among the definitions you have explicitly marked as implicit.

Page 8: Implicit conversion and parameters

Scope RuleAn inserted implicit conversion must be in scope as a single identifier, or be associated with the source or target type of the conversion

The Scala compiler will only consider implicit conversions that are in scope. To make an implicit conversion available, therefore, you must in some way bring it into scope

Page 9: Implicit conversion and parameters

Non-Ambiguity Rule An implicit conversion is only inserted if there is no other possible conversion to insert.

If the compiler has two options to fix x + y, say using either convert1(x) + y or convert2(x) + y, then it will report an error and refuse to choose between them.

Page 10: Implicit conversion and parameters

Explicits-First RuleWhenever code type checks as it is written, no

implicits are attempted.

The compiler will not change code that already works.

Page 11: Implicit conversion and parameters

One-at-a-time Rule

Only one implicit is tried. The compiler will never rewrite x + y to convert1(convert2(x)) + y.

Doing so would cause compile times to increase dramatically on erroneous code .

Page 12: Implicit conversion and parameters

Naming an implicit conversion.object MyConversions {

implicit def stringWrapper(s: String):

RandomAccessSeq[Char] = ...

implicit def intToString(x: Int): String = ...

}

import MyConversions.stringWrapper

... // code making use of stringWrapper

In this example, it was important that the implicit conversions had names,

because only that way could you selectively import one and not the other.

Page 13: Implicit conversion and parameters

Where implicits are triedThere are three places implicits are used in theLanguage

conversions to an expected type.

conversions of the receiver of a selection.

implicit parameters.

Page 14: Implicit conversion and parameters

Implicit conversion to an expected type

def printWithSpaces(seq: RandomAccessSeq[Char]) = seq mkString " "

println(printWithSpaces("Hello"))

Page 15: Implicit conversion and parameters

Converting the receiversuppose you write down obj.doIt, and obj does

not have a member named doIt. The compiler will try to insert conversions

before giving up. In this case, the conversion needs to apply to the receiver,

obj. The compiler will act as if the expected “type” of obj were “has a

member named doIt.

Page 16: Implicit conversion and parameters

Interoperable with new typesclass Rational(n: Int, d: Int) {

def + (that: Rational): Rational = ...

def + (that: Int): Rational = ...

}

scala> 1 + oneHalf

<console>:6: error: overloaded method value + with

alternatives (Double)Double <and> ... cannot be applied

to (Rational)

1 + oneHalf

scala> implicit def intToRational(x: Int) =

new Rational(x, 1)

intToRational: (Int)Rational

scala> 1 + oneHalf

res6: Rational = 3/2●

Page 17: Implicit conversion and parameters

Simulating new syntaxThe other major use of implicit conversions is to simulate adding new syntax.

Recall that you can make a Map using syntax like this:

Map(1 -> "one", 2 -> "two", 3 -> "three")

Have you wondered how the -> is supported? It’s not syntax! Instead, -> is

a method of the class ArrowAssoc, a class defined inside the standard Scala preamble (scala.Predef)

Page 18: Implicit conversion and parameters

Implicit parametersThe remaining place the compiler inserts implicits is within argument lists.

The compiler will sometimes replace someCall(a) with someCall(a)(b),

or new SomeClass(a) with new SomeClass(a)(b), thereby adding a missing parameter list to complete a function call.

For example, if someCall’s missing last parameter list takes three parameters, the compiler will supply them implicitly

Page 19: Implicit conversion and parameters

Debugging implicitsSometimes you might wonder why the compiler did not find an implicit

conversion that you think should apply. In that case it helps to write the conversion out explicitly. If that also gives an error message, you then know why the compiler could not apply your implicit

scala> val chars: List[Char] = "xyz"

error: type mismatch; java.lang.String("xyz") required: List[Char]

scala> val chars: List[Char] = stringWrapper("xyz")

error: type mismatch;

found java.lang.Object with RandomAccessSeq[Char]

required: List[Char]

val chars: List[Char] = stringWrapper("xyz")

Page 20: Implicit conversion and parameters

Scala QuickPimpPatternclass ListFirstTen[T](xs: List[T]) { def

firstTen: List[T] = xs.slice(0, 9)

}

implicit def listToFirstTen[T](xs: List[T]) = new ListFirstTen[T](xs)

println(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12).firstTen)

Page 21: Implicit conversion and parameters

Thank you