I have two functions:
override def build_url(dbType: DbDriverType, dbAddr: String, dbName: String): F[DbAddr] = dbType match {
case PostgresSql =>
Applicative[F].pure(DbAddr("jdbc:postgresql://" |+| dbAddr |+| "/" |+| dbName))
case _ => DbDriverError.raiseError[F, DbAddr]
}
override def get_db_driver(dbType: DbDriverType): F[DbDriver] = dbType match {
case PostgresSql =>
Applicative[F].pure(DbDriver("org.postgresql.Driver"))
case _ => Applicative.raiseError[F, DbDriver](DbDriverError)
}
The first compiles and the second not. The compiler complains:
[error] found : io.databaker.db.DbDriverError.type
[error] required: cats.ApplicativeError[F, _ >: cats.Applicative.type]
[error] case _ => Applicative.raiseError[F, DbDriver](DbDriverError)
On the first function, I use on DbDriverError.raiseError[F, DbAddr]
the extension method and on the second not. For me, it should be the same.
What is the difference?
On the second case Applicative.raiseError[F, DbDriver](DbDriverError)
you are using extension method on Applicative
compaion object. So this
Applicative.raiseError[F, DbDriver](DbDriverError)
is virtually this
new ApplicativeErrorIdOps[F, Applicative.type](Applicative).raiseError[DbDriver](DbDriverError)(implicitly[ApplicativeError[F, Applicative.type]])
Obviously there is no ApplicativeError[F, Applicative.type]
instance, if your code is similar to @Luis Miguel Mejía Suárez's scastei, then there is ApplicativeError[F, Throwable]
in the form of Sync[F]
.
On the first example it works because DbDriverError.raiseError[F, DbAddr]
is the extension method which performs
new ApplicativeErrorIdOps[F, DbDriverError.type](DbDriverError).raiseError[DbAddr](DbDriverError)(implicitly[ApplicativeError[F, DbDriverError.type]])
assuming that object DbDriverError extends Exception
(or some other Throwable
) it is equal to directly calling
implicitly[ApplicativeError[F, Throwable]].raiseError[DbAddr](DbDriverError)
where this implicit could also take MonadError[F, Throwable]
, Sync[F]
or any other implementeation of ApplicativeError[F, Throwable]
. Since companions have summon method you could just write:
ApplicativeError[F, Throwable].raiseError[DbDriver](DbDriverError)
// not the same as
// Applicative.raiseError[F, DbDriver](DbDriverError)
// !!!
// See where are square brackets and type parameters!
// And the class doesn't even match!
TLDR:
Applicative[F].sth
(calling Applicative.apply[F[_]](implicit a: Applicative[F]): Applicative[F]
is not the same as Applicative.sth
(calling method/extension method on Applicative
companion object, especially if we need a method from ApplicativeError
that isn't defined on Applicative
).