Skip to content

Instantly share code, notes, and snippets.

@jamesyang124
Last active February 15, 2023 11:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jamesyang124/13e56e57318560b12df29802d1b14d1f to your computer and use it in GitHub Desktop.
Save jamesyang124/13e56e57318560b12df29802d1b14d1f to your computer and use it in GitHub Desktop.
Scala take away #1 - https://youtu.be/yYo0gANYViE

Why typeclass?

Polymorphism and Decoupling.

Polymorphism

  1. Parametric

List of Int, list of Double, types are as type parameters in a context(List), not as types of direct values(without context) which infer the idea of ad-hoc polymorphism

  1. Ad-hoc polymorphism

Typeclass addresses the problems that ad-hoc polymorphism where your operations want to potentially do something different for the different types of values that it accepts. Typeclass aim to decouple ad hoc polymorphism

Overloading

The method name, which represent as behaviour, not required to be the same. This is a very weak link to the concept of type polymorphism.

Pattern matching

a.k.a typecasing.

Implicit parameters

In order to load the typeclass automatically, inject the type class instance(implicit object implements that type class) as implicit parameter.

Implicit conversion with implicit parameter

implicit def ListIsSerializable[T](implicit ev: Serializable[T]) = ....

// shorthand to
implicit def ListIsSerializable[T : Serializable] = 
  new Serializable[List[T]] {
    def ser(xs: List[T]) = xs.map(serialize(_)).mkString("List(",",",")")
  }

serialize(List(Person("Seth", 1), Person("Some", 2)))
// String = List(Person(Seth, 1), Person(Some, 2))

OO style

implicit def addSerializable[T](n: T)(implicit s: Serializable[T]) = 
  new { def serialize = s.sert(n) }

The new keyword without class name, is as creating an object of anonymous class.

http://stackoverflow.com/questions/9727637/new-keyword-in-scala

Disambiguating

You might have implicit parameters defined same return type repeatedly. Though the ambiguity would happened when we not explicitly supplied which implicit parameter we use. We can pass that implicit parameter as higher order function's last input to resolve this issue:

case class SomeClass() {
  def shouldBeHigherOrder(v: Int)(implicit x: Z) = ....
}


implicit val z1 = Z.map(_.anotherZ)
implicit val z2 = Z.map(_.someZ)

instanceOfSomeClass.shouldBeHigherOrder(5)
// ambiguous implicit values

instanceOfSomeClass.shouldBeHigherOrder(5)(z1)
// imp. with _.anotherZ

instanceOfSomeClass.shouldBeHigherOrder(5)(z2)
// imp. with _.someZ

It should be a good practice that putting implicit parameters to higher order function's last input.

Type class, pattern matching, oo dispatch actions

Type class works at compile time only. Others are at run time.

So if the type information lost, compiler will try to find the most reasonable type def. for it, unfortunatelly it should be Any type in most cases.

Downsides

Performance penalties occurred because of adding extra layer of method call.

Extending reading - What means about type-safe?

https://www.quora.com/What-does-it-mean-if-a-language-is-type-safe

"Type safe" usually refers to languages that ensure that an operation is working on the right kind of data at some point before the operation is actually performed. This may be at compile time or at run time.

This is mainly in contrast to languages that are not "type safe", what you might call "type unsafe" languages. In assembler and C you can often treat a pointer as an integer, an integer as a string, a 2-byte integer as a 4-byte integer, or series of bytes as a structure.

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