Skip to content

Instantly share code, notes, and snippets.

@sshark
Last active August 29, 2015 14:14
Show Gist options
  • Select an option

  • Save sshark/48f43ebc926655b78453 to your computer and use it in GitHub Desktop.

Select an option

Save sshark/48f43ebc926655b78453 to your computer and use it in GitHub Desktop.
Examples of implicit usages
val sampleInts = List(1,2,3,4)
val sampleStrings = List("AA", "BB", "CC")
import annotation.implicitNotFound
@implicitNotFound("Member of type class ${T} not found.")
trait Joinable[T] {
def join(l: List[T]): T
}
implicit object JoinStrings extends Joinable[String] {
override def join(strings: List[String]) = {
println("Joining the strings...")
strings.reduce(_ + _)
}
}
object StringUtils {
implicit object JoinInts extends Joinable[Int] {
override def join(ints: List[Int]) = {
println("Joining the ints...")
ints.foldLeft("")(_.toString + _.toString).toInt
}
}
}
object JoinAll {
def cat(strings: List[String])(implicit ev: Joinable[String]) = ev.join(strings)
def cat(ints: List[Int])(implicit ev: Joinable[Int]) = ev.join(ints)
def cat(symbols: List[Symbol])(implicit ev: Joinable[Symbol]) = ev.join(symbols)
}
// using 'object' to localize imports i.e. StringUtils._ otherwise it will conflicts with
// IntsUtils._ which share the same namespace further down this source file.
object ExampleA {
def run {
println("Running example A...")
import JoinAll._
import StringUtils._
println(cat(sampleStrings)) // step A
println(cat(sampleInts)) // step B
// uncomment next line to show custom annotation error message during compilation
// cat(List('a, 'b, 'c))
}
}
ExampleA.run
// OR better, use type parameter to collapse these functions. 'implicitly' is a function
// defined in Predef. It is a syntactical sugar for the implicit curry form.
object Collasped {
def cat[T:Joinable](strings: List[T]) = implicitly[Joinable[T]].join(strings)
// or use the previous form mentioned above but with type parameter
// def cat[T](strings: List[T])(implicit ev: Joinable[T]) = ev.join(strings)
}
object ExampleB {
def run {
println("Running example B...")
import Collasped._
import StringUtils._
println(cat(sampleStrings)) // step C
println(cat(sampleInts)) // step D
}
}
ExampleB.run
// another example with new implicit object
object IntsUtils {
implicit object SumInts extends Joinable[Int] {
override def join(ints: List[Int]) = {
println("Summing the ints...")
ints.reduce(_ + _)
}
}
}
object ExampleC {
def run {
println("Running example C...")
import Collasped._
import IntsUtils._
println(cat(sampleInts)) // step C
// compare to the result in step B, it should be 10 instead of "1234"
}
}
ExampleC.run
// pimp my library (add new method to exisitng class)
import java.util.Locale
import java.text.Collator
import scala.language.implicitConversions
trait CanCompare[T] { def compare(a:T, b:T): Boolean }
trait Comparable[T] { def =<(other: T): Boolean }
implicit object SpanishStrings extends CanCompare[String] {
val collator = Collator.getInstance(new Locale("ES"))
def compare(a: String, b: String) = collator.compare(a,b) <= 0
}
implicit def order[T](a:T)(implicit c: CanCompare[T]) = {
new Comparable[T] {
def =<(b: T) = c.compare(a, b)
}
}
println("aa" =< "bb")
println("ccc" =< "bb")
// functor (for containers)
trait Functor[F[_]] {
def map[X,Y](f: X => Y): F[X] => F[Y]
def get[X](i: Int): F[X] => Option[X]
}
import java.util.ArrayList
import java.util.List
import java.util.Arrays
//implicit object JAL_a_Functor extends Functor[ArrayList] {
implicit object JAL_a_Functor extends Functor[List] {
def map[X,Y](f: X => Y) = (xs: List[X]) => {
val ys = new ArrayList[Y]
for (i <- 0 until xs.size) ys.add(f(xs.get(i)))
ys
}
def get[X](i: Int) = (xs: List[X]) => {
if (i > xs.size - 1) None else Some(xs.get(i))
}
}
implicit def fops[F[_]: Functor, A](fa: F[A]) = new {
val witness = implicitly[Functor[F]]
final def map[B](f: A => B): F[B] = witness.map(f)(fa)
final def getIt(i: Int): Option[A] = witness.get(i)(fa)
}
//val testList = new ArrayList(Arrays.asList("this", "is", "a", "test"))
val testList = Arrays.asList("this", "is", "a", "test")
val transformed = testList.map(_.toUpperCase)
// have to use method names not found in the current class otherwise implicit won't work
println(transformed)
println(transformed.getIt(2).map(t => s"#${t}").get)
println(transformed.getIt(3).map(t => s"#${t}").get)
println(transformed.getIt(4).map(t => s"#${t}").getOrElse("#EMPTY"))
/* alternately Functor can be written like this,
trait Functor[M[_]] {
def map[A, B](f: A => B, a: M[A]): M[B]
}
implicit object ListFunctor extends Functor[List] {
def map[A, B](f: A => B, a: List[A]): List[B] = a.map(f)
}
def f(l: List[Int])(implicit f: Functor[List]) = f.map((x: Int) => x * 2, l)
def g(l: List[String])(implicit f: Functor[List]) = f.map((x: String) => "@@" + x + "@@", l)
println(f(List(1,2,3)))
println(g(List("a", "b", "c")))
*/
// another method to handle type erasure from generic container
case class M[A](val i: A)
abstract class Twice {
type Result
def apply(): Result
}
implicit def twiceInt(i: M[Int]) = new Twice {
type Result = Int
override def apply(): Result = i.i * 2
}
implicit def twiceDouble(i: M[Double]) = new Twice {
type Result = Double
override def apply(): Result = i.i * 2.0
}
def twice(i: Twice): i.Result = i()
println(twice(M(2.0)))
println(twice(M(2)))
@sshark

sshark commented Feb 3, 2015

Copy link
Copy Markdown
Author

This is a complete Scala script where you can run it off command line i.e. scala pimp-my-libs.scala

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment