From fdfcb5799d9fd71b9c8e0abc7635b5e29ea59f09 Mon Sep 17 00:00:00 2001 From: Ghildiyal Date: Wed, 17 Jan 2018 16:41:50 +0530 Subject: [PATCH 1/2] Rewrote implicits section of the tour #746 --- _tour/implicit-conversions.md | 12 ++-- _tour/implicit-parameters.md | 35 +++++------ _tour/implicits.md | 110 ++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 28 deletions(-) create mode 100644 _tour/implicits.md diff --git a/_tour/implicit-conversions.md b/_tour/implicit-conversions.md index 0d77d73f7c..c2efa3fb09 100644 --- a/_tour/implicit-conversions.md +++ b/_tour/implicit-conversions.md @@ -1,16 +1,14 @@ --- -layout: tour +layout: tutorial title: Implicit Conversions -discourse: true - -partof: scala-tour +disqus: true +tutorial: scala-tour +categories: tour num: 27 next-page: polymorphic-methods previous-page: implicit-parameters - -redirect_from: "/tutorials/tour/implicit-conversions.html" --- An implicit conversion from type `S` to type `T` is defined by an implicit value which has function type `S => T`, or by an implicit method convertible to a value of that type. @@ -58,4 +56,4 @@ To turn off the warnings take either of these actions: * Import `scala.language.implicitConversions` into the scope of the implicit conversion definition * Invoke the compiler with `-language:implicitConversions` -No warning is emitted when the conversion is applied by the compiler. +No warning is emitted when the conversion is applied by the compiler. \ No newline at end of file diff --git a/_tour/implicit-parameters.md b/_tour/implicit-parameters.md index 0a3da1634a..2fa9e7cc17 100644 --- a/_tour/implicit-parameters.md +++ b/_tour/implicit-parameters.md @@ -1,16 +1,14 @@ --- -layout: tour +layout: tutorial title: Implicit Parameters -discourse: true - -partof: scala-tour +disqus: true +tutorial: scala-tour +categories: tour num: 26 next-page: implicit-conversions -previous-page: self-types - -redirect_from: "/tutorials/tour/implicit-parameters.html" +previous-page: explicitly-typed-self-references --- A method with _implicit parameters_ can be applied to arguments just like a normal method. In this case the implicit label has no effect. However, if such a method misses arguments for its implicit parameters, such arguments will be automatically provided. @@ -21,15 +19,18 @@ The actual arguments that are eligible to be passed to an implicit parameter fal * Second, eligible are also all members of companion modules of the implicit parameter's type that are labeled implicit. In the following example we define a method `sum` which computes the sum of a list of elements using the monoid's `add` and `unit` operations. Please note that implicit values can not be top-level, they have to be members of a template. - + ```tut +/** This example uses a structure from abstract algebra to show how implicit parameters work. A semigroup is an algebraic structure on a set A with an (associative) operation, called add here, that combines a pair of A's and returns another A. */ abstract class SemiGroup[A] { def add(x: A, y: A): A } +/** A monoid is a semigroup with a distinguished element of A, called unit, that when combined with any other element of A returns that other element again. */ abstract class Monoid[A] extends SemiGroup[A] { def unit: A } object ImplicitTest extends App { + /** To show how implicit parameters work, we first define monoids for strings and integers. The implicit keyword indicates that the corresponding object can be used implicitly, within this scope, as a parameter of a function marked implicit. */ implicit object StringMonoid extends Monoid[String] { def add(x: String, y: String): String = x concat y def unit: String = "" @@ -38,28 +39,20 @@ object ImplicitTest extends App { def add(x: Int, y: Int): Int = x + y def unit: Int = 0 } + /** This method takes a List[A] returns an A which represent the combined value of applying the monoid operation successively across the whole list. Making the parameter m implicit here means we only have to provide the xs parameter at the call site, since if we have a List[A] we know what type A actually is and therefore what type Monoid[A] is needed. We can then implicitly find whichever val or object in the current scope also has that type and use that without needing to specify it explicitly. */ def sum[A](xs: List[A])(implicit m: Monoid[A]): A = if (xs.isEmpty) m.unit else m.add(xs.head, sum(xs.tail)) - println(sum(List(1, 2, 3))) // uses IntMonoid implicitly - println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly + /** Here we call sum twice, with only one parameter each time. Since the second parameter of sum, m, is implicit its value is looked up in the current scope, based on the type of monoid required in each case, meaning both expressions can be fully evaluated. */ + println(sum(List(1, 2, 3))) // uses IntMonoid implicitly + println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly } ``` -This example uses a structure from abstract algebra to show how implicit parameters work. A semigroup, modeled by `SemiGroup` here, is an algebraic structure on a set of `A` with an (associative) operation, called `add` here, that combines a pair of `A`s and returns another `A`. - -A monoid, modeled by `Monoid` here, is a semigroup with a distinguished element of `A`, called `unit`, that when combined with any other element of `A` returns that other element again. - -To show how implicit parameters work, we first define monoids `StringMonoid` and `IntMonoid` for strings and integers, respectively. The `implicit` keyword indicates that the corresponding object can be used implicitly, within this scope, as a parameter of a function marked implicit. - -Method `sum` takes a `List[A]` and returns an `A`, which represents the result of applying the monoid operation successively across the whole list. Making the parameter `m` implicit here means we only have to provide the `xs` parameter at the call site, since if we have a `List[A]` we know what type `A` actually is and therefore what type `Monoid[A]` is needed. We can then implicitly find whichever `val` or `object` in the current scope also has that type and use that without needing to specify it explicitly. - -Finally, we call `sum` twice, with only one parameter each time. Since the second parameter of `sum`, `m`, is implicit, its value is looked up in the current scope, based on the type of monoid required in each case, meaning both expressions can be fully evaluated. - Here is the output of the Scala program: ``` 6 abc -``` +``` \ No newline at end of file diff --git a/_tour/implicits.md b/_tour/implicits.md new file mode 100644 index 0000000000..e7b65d5145 --- /dev/null +++ b/_tour/implicits.md @@ -0,0 +1,110 @@ +--- +layout: tutorial +title: Implicits + +disqus: true + +tutorial: scala-tour +categories: tour +num: 26 +next-page: implicit-conversions +previous-page: explicitly-typed-self-references +--- +Implicits allow for automatic application of code when an explicit application isn't supplied. + +## Implicit parameters + +Implicit parameters allow for the caller to omit an argument if an implicit one is in scope. Use the `implicit` keyword to make a value, object, or expression implicit. You also use it to make the parameter list implicit. +```tut +class Greeting(val greeting: String) { + def greet(name: String) = s"$greeting, $name" +} +implicit val standardGreeting = new Greeting("Hello") + + +def printGreeting(name: String)(implicit greeting: Greeting) = greeting.greet(name) + + +printGreeting("Franchesca") // Hello, Franchesca +printGreeting("Fred")(new Greeting("Good day")) // Good day, Fred +``` +In method 'printGreeting', second parameter 'greeting' is an implicit parameter,which means if caller doesn't supply it explicitly then compiler would look for an implicit value in the scope. +In first call to 'printGreeting' above, we don't supply second parameter(a Greeting),which makes compiler to look for implicit parameter in the scope and it finds implicit val 'standardGreeting'. +In second call to 'printGreeting', we explicitly provide second parameter and hence 'standardGreeting' is not needed. + +This becomes useful when you have a lot of similar arguments to function calls throughout your program. +Implicits may be problematic in two ways.Primary problem is that they hide an argument that can impact your program, making it less obvious what your methods depend upon because the method call doesn't show you that anything is going on. +Also,implicits can make code more difficult to understand because it's not always obvious where they're defined if you import them from another module with a wildcard (e.g. `import MyPredef._`). + + + + +## Implicit conversion + + +Implicit Conversions are a set of methods that Scala tries to apply when it encounters an object of the wrong type being used. +``` +(1 to 5).foreach(println) // print out 1 2 3 4 5 +``` +In code above,method 'to' defined in the RichInt class is called and it returns a Range object,on which we then call 'foreach' method. +But Int doesn't have 'to' method.So what is happening here?Under the hood int is converted to RichInt implicitly. +This typecasting happens because of the method `implicit def intWrapper(x: Int): RichInt` defined in `Predef`. + +Implicits conversions can be useful when you're making a lot of calls to an API and the calls are verbose or require a type conversion. For example, if you want to create a button using Java swing, the code is verbose: +```tut +import scala.language.implicitConversions +import java.awt.event.{ActionEvent, ActionListener} +import javax.swing.JButton + +val button = new JButton +button.addActionListener( + new ActionListener { + def actionPerformed(event: ActionEvent) = { + println("pressed!") + } + } +) +``` +You would need to write this same code for every button in order to _print "pressed" when the button is pressed_. You could instead abstract this away to an implicit conversion: +```tut +import java.awt.event.{ActionEvent, ActionListener} +import javax.swing.JButton + +implicit def function2ActionListener(f: ActionEvent => Unit) = + new ActionListener { + def actionPerformed(event: ActionEvent) = f(event) + } + + +val button = new JButton +button.addActionListener( + (_: ActionEvent) => println("pressed!") +) +``` +The implicit method `function2ActionListener` takes a function which accepts an ActionEvent. It then returns an `ActionListener` with the aforementioned function as its `actionPerformed`. Now when we call `button.addActionListener` (which accepts an `ActionListener`) with an anonymous function of type `ActionEvent => Unit`, the compiler looks for an implicit conversion function which can convert the type to `ActionListener`. + +This removes a lot of the boilerplate because we can use an anonymous function. However, because implicits are often defined outside of the package, it can be difficult to debug. Therefore they are best used in libraries. + +Scala also allows Implicit classes, which can be used to extend the functionality of objects without modifying the source code of the object. +For example, we can have something like this: +```tut +object ImplicitClassDemo { + + implicit class StringImprovements(val s: String) { + def increment = s.map(c => (c + 1).toChar) + } + + def main(args: Array[String]): Unit = { + val x = "Einsteim" + println("Einstein".increment) + } +} +``` +Here, making use of implicit class 'StringImprovements' we are able to add a new behavior('increment') to String object. +An implicit class must be defined in a scope where method definitions are allowed (not at the top level). +This means an implicit class must be defined in either of: +* A class +* An object +* A package object + +_Example Credit_: Odersky, Martin, Lex Spoon, and Bill Venners. Programming in Scala. Walnut Creek, CA: Artima, 2016. \ No newline at end of file From 2ad5a673e2cdf88a5450ca963379543075d1257d Mon Sep 17 00:00:00 2001 From: Ghildiyal Date: Wed, 17 Jan 2018 16:41:50 +0530 Subject: [PATCH 2/2] Rewrote implicits section of the tour #746 --- _tour/implicit-conversions.md | 2 +- _tour/implicit-parameters.md | 32 +++++----- _tour/implicits.md | 112 ++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 _tour/implicits.md diff --git a/_tour/implicit-conversions.md b/_tour/implicit-conversions.md index 0d77d73f7c..00aa3f1971 100644 --- a/_tour/implicit-conversions.md +++ b/_tour/implicit-conversions.md @@ -58,4 +58,4 @@ To turn off the warnings take either of these actions: * Import `scala.language.implicitConversions` into the scope of the implicit conversion definition * Invoke the compiler with `-language:implicitConversions` -No warning is emitted when the conversion is applied by the compiler. +No warning is emitted when the conversion is applied by the compiler. \ No newline at end of file diff --git a/_tour/implicit-parameters.md b/_tour/implicit-parameters.md index 0a3da1634a..baa9ac8fb2 100644 --- a/_tour/implicit-parameters.md +++ b/_tour/implicit-parameters.md @@ -21,14 +21,25 @@ The actual arguments that are eligible to be passed to an implicit parameter fal * Second, eligible are also all members of companion modules of the implicit parameter's type that are labeled implicit. In the following example we define a method `sum` which computes the sum of a list of elements using the monoid's `add` and `unit` operations. Please note that implicit values can not be top-level, they have to be members of a template. - +This example uses a structure from abstract algebra to show how implicit parameters work. +A semigroup is an algebraic structure on a set A with an (associative) operation, called add here, that combines a pair of A's and returns another A. + ```tut abstract class SemiGroup[A] { def add(x: A, y: A): A } +``` + +A monoid is a semigroup with a distinguished element of A, called unit, that when combined with any other element of A returns that other element again. +```tut abstract class Monoid[A] extends SemiGroup[A] { def unit: A } +``` + +To show how implicit parameters work, we first define monoids for strings and integers. The implicit keyword indicates that the corresponding object can be used implicitly, within this scope, as a parameter of a function marked implicit. + +```tut object ImplicitTest extends App { implicit object StringMonoid extends Monoid[String] { def add(x: String, y: String): String = x concat y @@ -38,28 +49,21 @@ object ImplicitTest extends App { def add(x: Int, y: Int): Int = x + y def unit: Int = 0 } + def sum[A](xs: List[A])(implicit m: Monoid[A]): A = if (xs.isEmpty) m.unit else m.add(xs.head, sum(xs.tail)) - println(sum(List(1, 2, 3))) // uses IntMonoid implicitly - println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly + println(sum(List(1, 2, 3))) // uses IntMonoid implicitly + println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly } ``` - -This example uses a structure from abstract algebra to show how implicit parameters work. A semigroup, modeled by `SemiGroup` here, is an algebraic structure on a set of `A` with an (associative) operation, called `add` here, that combines a pair of `A`s and returns another `A`. - -A monoid, modeled by `Monoid` here, is a semigroup with a distinguished element of `A`, called `unit`, that when combined with any other element of `A` returns that other element again. - -To show how implicit parameters work, we first define monoids `StringMonoid` and `IntMonoid` for strings and integers, respectively. The `implicit` keyword indicates that the corresponding object can be used implicitly, within this scope, as a parameter of a function marked implicit. - -Method `sum` takes a `List[A]` and returns an `A`, which represents the result of applying the monoid operation successively across the whole list. Making the parameter `m` implicit here means we only have to provide the `xs` parameter at the call site, since if we have a `List[A]` we know what type `A` actually is and therefore what type `Monoid[A]` is needed. We can then implicitly find whichever `val` or `object` in the current scope also has that type and use that without needing to specify it explicitly. - -Finally, we call `sum` twice, with only one parameter each time. Since the second parameter of `sum`, `m`, is implicit, its value is looked up in the current scope, based on the type of monoid required in each case, meaning both expressions can be fully evaluated. +Method sum[A] takes a List[A] returns an A which represent the combined value of applying the monoid operation successively across the whole list. Making the parameter m implicit here means we only have to provide the xs parameter at the call site, since if we have a List[A] we know what type A actually is and therefore what type Monoid[A] is needed. We can then implicitly find whichever val or object in the current scope also has that type and use that without needing to specify it explicitly. +Here we call sum twice, with only one parameter each time. Since the second parameter of sum, m, is implicit its value is looked up in the current scope, based on the type of monoid required in each case, meaning both expressions can be fully evaluated. Here is the output of the Scala program: ``` 6 abc -``` +``` \ No newline at end of file diff --git a/_tour/implicits.md b/_tour/implicits.md new file mode 100644 index 0000000000..cdae2e0bfb --- /dev/null +++ b/_tour/implicits.md @@ -0,0 +1,112 @@ +--- +layout: tour +title: Implicits + +discourse: true + +partof: scala-tour + +num: 26 +next-page: implicit-conversions +previous-page: explicitly-typed-self-references + +redirect_from: "/tutorials/tour/implicits.html" +--- +Implicits allow for automatic application of code when an explicit application isn't supplied. + +## Implicit parameters + +Implicit parameters allow for the caller to omit an argument if an implicit one is in scope. Use the `implicit` keyword to make a value, object, or expression implicit. You also use it to make the parameter list implicit. +```tut +class Greeting(val greeting: String) { + def greet(name: String) = s"$greeting, $name" +} +implicit val standardGreeting = new Greeting("Hello") + + +def printGreeting(name: String)(implicit greeting: Greeting) = greeting.greet(name) + + +printGreeting("Franchesca") // Hello, Franchesca +printGreeting("Fred")(new Greeting("Good day")) // Good day, Fred +``` +In method 'printGreeting', second parameter 'greeting' is an implicit parameter,which means if caller doesn't supply it explicitly then compiler would look for an implicit value in the scope. +In first call to 'printGreeting' above, we don't supply second parameter(a Greeting),which makes compiler to look for implicit parameter in the scope and it finds implicit val 'standardGreeting'. +In second call to 'printGreeting', we explicitly provide second parameter and hence 'standardGreeting' is not needed. + +This becomes useful when you have a lot of similar arguments to function calls throughout your program. +Implicits may be problematic in two ways.Primary problem is that they hide an argument that can impact your program, making it less obvious what your methods depend upon because the method call doesn't show you that anything is going on. +Also,implicits can make code more difficult to understand because it's not always obvious where they're defined if you import them from another module with a wildcard (e.g. `import MyPredef._`). + + + + +## Implicit conversion + + +Implicit Conversions are a set of methods that Scala tries to apply when it encounters an object of the wrong type being used. +``` +(1 to 5).foreach(println) // print out 1 2 3 4 5 +``` +In code above,method 'to' defined in the RichInt class is called and it returns a Range object,on which we then call 'foreach' method. +But Int doesn't have 'to' method.So what is happening here?Under the hood int is converted to RichInt implicitly. +This typecasting happens because of the method `implicit def intWrapper(x: Int): RichInt` defined in `Predef`. + +Implicits conversions can be useful when you're making a lot of calls to an API and the calls are verbose or require a type conversion. For example, if you want to create a button using Java swing, the code is verbose: +```tut +import scala.language.implicitConversions +import java.awt.event.{ActionEvent, ActionListener} +import javax.swing.JButton + +val button = new JButton +button.addActionListener( + new ActionListener { + def actionPerformed(event: ActionEvent) = { + println("pressed!") + } + } +) +``` +You would need to write this same code for every button in order to _print "pressed" when the button is pressed_. You could instead abstract this away to an implicit conversion: +```tut +import java.awt.event.{ActionEvent, ActionListener} +import javax.swing.JButton + +implicit def function2ActionListener(f: ActionEvent => Unit) = + new ActionListener { + def actionPerformed(event: ActionEvent) = f(event) + } + + +val button = new JButton +button.addActionListener( + (_: ActionEvent) => println("pressed!") +) +``` +The implicit method `function2ActionListener` takes a function which accepts an ActionEvent. It then returns an `ActionListener` with the aforementioned function as its `actionPerformed`. Now when we call `button.addActionListener` (which accepts an `ActionListener`) with an anonymous function of type `ActionEvent => Unit`, the compiler looks for an implicit conversion function which can convert the type to `ActionListener`. + +This removes a lot of the boilerplate because we can use an anonymous function. However, because implicits are often defined outside of the package, it can be difficult to debug. Therefore they are best used in libraries. + +Scala also allows Implicit classes, which can be used to extend the functionality of objects without modifying the source code of the object. +For example, we can have something like this: +```tut +object ImplicitClassDemo { + + implicit class StringImprovements(val s: String) { + def increment = s.map(c => (c + 1).toChar) + } + + def main(args: Array[String]): Unit = { + val x = "Einsteim" + println("Einstein".increment) + } +} +``` +Here, making use of implicit class 'StringImprovements' we are able to add a new behavior('increment') to String object. +An implicit class must be defined in a scope where method definitions are allowed (not at the top level). +This means an implicit class must be defined in either of: +* A class +* An object +* A package object + +_Example Credit_: Odersky, Martin, Lex Spoon, and Bill Venners. Programming in Scala. Walnut Creek, CA: Artima, 2016. \ No newline at end of file