Skip to content

Instantly share code, notes, and snippets.

@mikea
Last active December 27, 2015 03:29
Show Gist options
  • Save mikea/7259269 to your computer and use it in GitHub Desktop.
Save mikea/7259269 to your computer and use it in GitHub Desktop.
I want C[T] to have different method sets based on T. I thought I could use implicits, but can't make it work. Any idea how to fix this example?
class Printer[T](_t: T) {
def t = _t
def print():Unit = { println(t) }
}
class IterablePrinter[T, I <: Iterable[T]](p : Printer[I]) {
def printEach() = p.t.foreach(println)
}
object Test extends App {
new Printer(100).print()
new Printer(List(1, 2, 3)).print()
new IterablePrinter[Int, List[Int]](new Printer(List(1, 2, 3))).printEach()
// Define implicits to make this work:
new Printer(List(1, 2, 3)).printEach()
}
@ConnorDoyle
Copy link

Idiomatically, the implicit conversion might reside within object Printer { object Implicits { /* ... */ }} so you can bring them into scope with import Printer.Implicits._.

It's sufficient to import scala.languageFeature.implicitConversions, no need for the compiler flag.

@vigdorchik
Copy link

trait Printable {
  def print(): Unit
}

object Implicits {
  implicit class AnyRefPrinter(obj: AnyRef) extends Printable {
    def print() = Console.println(obj.toString)
  }

  implicit class IterablePrinter[T <% Printable](obj: Iterable[T]) extends Printable {
    def print() = obj foreach (_.print())
  }
}

import Implicits._

"Print me".print()
List("Print me too").print()

@vigdorchik
Copy link

bash-4.1$ scala printer.scala
Print me
Print me too

@sergey-scherbina
Copy link

object TestApp extends App {

  trait Printer[-T] {
    def print(p: T)
  }

  implicit class PrinterOp[T: Printer](val p: T) {
    def print = implicitly[Printer[T]].print(p)
  }

  trait LowPriorityPrinter {

    implicit object StdPrinter extends Printer[Any] {
      def print(p: Any) = println(p)
    }

  }

  object Printer extends LowPriorityPrinter {

    implicit object IterPrinter extends Printer[Iterable[_]] {
      def print(p: Iterable[_]) = p.foreach(_.print)
    }

  }

  "hello".print

  List("hello", "world").print

}

@mikea
Copy link
Author

mikea commented Nov 1, 2013

Guys, you are missing important point: the task is not for print to work differently, but to have an extra method that is present only when I can prove that T is iterable..

@sergey-scherbina
Copy link

object TestApp extends App {

  trait Printer[-T] {
    def print(p: T)
  }

  trait EachPrinter[-T] extends Printer[T] {
    def printEach(ps: Iterable[T])
  }

  implicit class PrinterOp[T: Printer](val p: T) {
    def print = implicitly[Printer[T]].print(p)
  }

  implicit class EachPrinterOp[T: EachPrinter](val p: Iterable[T]) {
    def printEach = implicitly[EachPrinter[T]].printEach(p)
  }

  object Printer {

    trait AnyPrinter extends Printer[Any] {
      def print(p: Any) = println(p)
    }

    implicit object AnyPrinter extends AnyPrinter

  }

  object EachPrinter {

    trait AnyEachPrinter extends EachPrinter[Any] with Printer.AnyPrinter {
      def printEach(p: Iterable[Any]) = p foreach print
    }

    implicit object AnyEachPrinter extends AnyEachPrinter

  }

  "hello".print
  //"hello".printEach  // Doesn't compile

  List("hello", "world").print
  List("hello", "world").printEach

}

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