- Covariant ( return type )
- Contravariant ( argument type )
Covariant type on contravariant position:
case class Box[+A](value: A) {
def set(a: A): Box[A] = Box(a)
}
Error:(4, 11) covariant type A occurs in contravariant position in type A of value a
def set(a: A): Box[A] = Box(a)
Why this should not compile ?
val catBox = new Box[Cat]
val animalBox: Box[Animal] = catBox
val dog = new Dog
animalBox.set(dog) // runtime-error: a box of cats contains a dog!
Principle of least power (you know what your code can and cannot do)
def foo[F[_]: Sync] = F.delay(db.read)
// Sync appears everywhere
def bar[F[_]: Sync] = foo.flatMap ...
vs
trait Db[F[_]] {
def read[A]: F[A]
}
object Db {
def apply[F[_]](implicit Db: Db[F]): Db[F] = Db
def create[F[_]: Sync] = new Db[F] { ... }
}
// Sync only appears close to the top level
def bar[F[_]: Db: Monad] = Db[F].read.flatMap ...
scala.String is just an alias for java.lang.String.
There's implicit def wrapString(s: String): WrappedString
at scala.Predef
object that is automatically imported.
WrappedString
allows treating String as an "efficient" IndexedSeq (subtype of Seq)