Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Tim McIver
@tmciver
Is this the right place to ask questions about the Scala with Cats book?
Rob Norris
@tpolecat
Sure! If it's specific to the book you may need to contact the authors but if it's about cats then yeah.
Fabio Labella
@SystemFw
@tpolecat ah yeah, sure. It's in my stack, which is very lazily evaluated ;)
Tim McIver
@tmciver

OK. My question is about implementing typeclasses. In the exercise for section 1.3 it shows how to implement syntax and has code like this:

object PrintableSyntax {
  implicit class PrintableOps[A](value: A) {
    def format(implicit p: Printable[A]): String =
      Printable.format(value)

    def print(implicit p: Printable[A]): Unit =
      Printable.print(value)
  }
}

In my implementation, which I did before looking at the answer, was to callformat/print on the implicit p. Is that wrong? Is there a reason to prefer the way above?

Fabio Labella
@SystemFw
what does the above do? add functions to the companion object replicating each method in the typeclass?
(in the part that we don't see)
I would say that the way you did it is actually preferable
or at least more common
Tim McIver
@tmciver
It's to add extension methods to any type that has a Printable instance. The calls above are to methods in the Printable companion object:
object Printable {
  def format[A](input: A)(implicit p: Printable[A]): String =
    p.format(input)

  def print[A](input: A)(implicit p: Printable[A]): Unit =
    println(format(input))
}
And my implementation was just:
object PrintableSyntax {
  implicit class PrintableOps[A](a: A) {
    def format(implicit printer: Printable[A]): String = printer.format(a)
    def print(implicit printer: Printable[A]): Unit = println(format)
  }
}
Fabio Labella
@SystemFw
right
that's what I thought
your way is more common
Tim McIver
@tmciver
OK, thanks.
Fabio Labella
@SystemFw
you can add methods to the object as well (I know some people that do it), but it's not really necessary (and adds a bit of boilerplate)
Tim McIver
@tmciver
@SystemFw can you expand on that? Do you mean they add the implicit class to the Printable companion object?
Fabio Labella
@SystemFw
no, I mean exactly what you pasted :)
your first code snippet
they are adding each method that's already present in the Printable typeclass to the printable companion object
do you see it?
object Printable {
  def format[A](input: A)(implicit p: Printable[A]): String =
    p.format(input)

  def print[A](input: A)(implicit p: Printable[A]): Unit =
    println(format(input))
}
this bit
I assume this is the trait
Tim McIver
@tmciver
Yup. OK, I see.
Fabio Labella
@SystemFw
trait Printable[A] {
  def format(input: A): String 
  def print(input: A) : Unit
}
do you also know why they do it?
(if not, I can explain, and I can tell you a more common alternative)
Tim McIver
@tmciver
I think because those methods are automatically imported when the trait is imported . . . ?
Fabio Labella
@SystemFw
the trait is not imported anywhere
Tim McIver
@tmciver
The book probably said but now I forget! :|
Fabio Labella
@SystemFw
ok, so imagine that the syntax bit doesn't exist for a second
say you have
def foo[A](a: A)(implicit p: Printable[A]): String = p.print(a)
makes sense so far?
Tim McIver
@tmciver
Yes
Fabio Labella
@SystemFw
this works, but generally you want to use context bounds because they are less noisy
they are just syntactic sugar so exactly equivalent
def foo[A: Printable](a: A): String = problem.print(a)
your evidence is not named so you can't really use the context bound
do you see?
Tim McIver
@tmciver
By "evidence" you mean the A: Printable part?
Fabio Labella
@SystemFw
you don't know how the Printable evidence is called (the compiler generates a fresh name when you use a context bound)
by "evidence" I mean the p in implicit p: Printable[A]
Tim McIver
@tmciver
OK, I see.
Fabio Labella
@SystemFw
the : Printable in A: Printable is called a context bound
Tim McIver
@tmciver
:thumbsup:
Fabio Labella
@SystemFw
and it's desugared into implicit $mangledCrazyName: Printable[P]
Tim McIver
@tmciver
And you have problem there because we don't have a name for the evidence?
Fabio Labella
@SystemFw
yeah
Tim McIver
@tmciver
Ah, I didn't know that desugaring.
Fabio Labella
@SystemFw
unless you revert to using an explicit implicit myName, which is noisy