diff --git a/core/src/main/scala/cats/syntax/applicative.scala b/core/src/main/scala/cats/syntax/applicative.scala index 322593327b..53e92664b7 100644 --- a/core/src/main/scala/cats/syntax/applicative.scala +++ b/core/src/main/scala/cats/syntax/applicative.scala @@ -2,16 +2,18 @@ package cats package syntax trait ApplicativeSyntax { - implicit def catsSyntaxApplicativeId[A](a: A): ApplicativeIdOps[A] = new ApplicativeIdOps[A](a) - implicit def catsSyntaxApplicative[F[_], A](fa: F[A])(implicit F: Applicative[F]): ApplicativeOps[F, A] = new ApplicativeOps[F, A](fa) + implicit final def catsSyntaxApplicativeId[A](a: A): ApplicativeIdOps[A] = + new ApplicativeIdOps[A](a) + implicit final def catsSyntaxApplicative[F[_], A](fa: F[A]): ApplicativeOps[F, A] = + new ApplicativeOps[F, A](fa) } final class ApplicativeIdOps[A](val a: A) extends AnyVal { def pure[F[_]](implicit F: Applicative[F]): F[A] = F.pure(a) } -final class ApplicativeOps[F[_], A](fa: F[A])(implicit F: Applicative[F]) { - def replicateA(n: Int): F[List[A]] = F.replicateA(n, fa) - def unlessA(cond: Boolean): F[Unit] = F.unlessA(cond)(fa) - def whenA(cond: Boolean): F[Unit] = F.whenA(cond)(fa) +final class ApplicativeOps[F[_], A](val fa: F[A]) extends AnyVal { + def replicateA(n: Int)(implicit F: Applicative[F]): F[List[A]] = F.replicateA(n, fa) + def unlessA(cond: Boolean)(implicit F: Applicative[F]): F[Unit] = F.unlessA(cond)(fa) + def whenA(cond: Boolean)(implicit F: Applicative[F]): F[Unit] = F.whenA(cond)(fa) } diff --git a/core/src/main/scala/cats/syntax/applicativeError.scala b/core/src/main/scala/cats/syntax/applicativeError.scala index 10dc9a6079..166adddab3 100644 --- a/core/src/main/scala/cats/syntax/applicativeError.scala +++ b/core/src/main/scala/cats/syntax/applicativeError.scala @@ -4,35 +4,34 @@ package syntax import cats.data.EitherT trait ApplicativeErrorSyntax { - implicit def catsSyntaxApplicativeErrorId[E](e: E): ApplicativeErrorIdOps[E] = + implicit final def catsSyntaxApplicativeErrorId[E](e: E): ApplicativeErrorIdOps[E] = new ApplicativeErrorIdOps(e) - implicit def catsSyntaxApplicativeError[F[_], E, A](fa: F[A])(implicit F: ApplicativeError[F, E]): ApplicativeErrorOps[F, E, A] = + implicit final def catsSyntaxApplicativeError[F[_], E, A](fa: F[A])(implicit F: ApplicativeError[F, E]): ApplicativeErrorOps[F, E, A] = new ApplicativeErrorOps[F, E, A](fa) - } -final class ApplicativeErrorIdOps[E](e: E) { +final class ApplicativeErrorIdOps[E](val e: E) extends AnyVal { def raiseError[F[_], A](implicit F: ApplicativeError[F, E]): F[A] = F.raiseError(e) } -final class ApplicativeErrorOps[F[_], E, A](fa: F[A])(implicit F: ApplicativeError[F, E]) { - def handleError(f: E => A): F[A] = +final class ApplicativeErrorOps[F[_], E, A](val fa: F[A]) extends AnyVal { + def handleError(f: E => A)(implicit F: ApplicativeError[F, E]): F[A] = F.handleError(fa)(f) - def handleErrorWith(f: E => F[A]): F[A] = + def handleErrorWith(f: E => F[A])(implicit F: ApplicativeError[F, E]): F[A] = F.handleErrorWith(fa)(f) - def attempt: F[Either[E, A]] = + def attempt(implicit F: ApplicativeError[F, E]): F[Either[E, A]] = F.attempt(fa) - def attemptT: EitherT[F, E, A] = + def attemptT(implicit F: ApplicativeError[F, E]): EitherT[F, E, A] = F.attemptT(fa) - def recover(pf: PartialFunction[E, A]): F[A] = + def recover(pf: PartialFunction[E, A])(implicit F: ApplicativeError[F, E]): F[A] = F.recover(fa)(pf) - def recoverWith(pf: PartialFunction[E, F[A]]): F[A] = + def recoverWith(pf: PartialFunction[E, F[A]])(implicit F: ApplicativeError[F, E]): F[A] = F.recoverWith(fa)(pf) } diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index 8d9be51c9e..2671087bf1 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait ApplySyntax1 { - implicit def catsSyntaxUApply[FA](fa: FA)(implicit U: Unapply[Apply, FA]): Apply.Ops[U.M, U.A] = + implicit final def catsSyntaxUApply[FA](fa: FA)(implicit U: Unapply[Apply, FA]): Apply.Ops[U.M, U.A] = new Apply.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/bitraverse.scala b/core/src/main/scala/cats/syntax/bitraverse.scala index e34372ade3..d24049def7 100644 --- a/core/src/main/scala/cats/syntax/bitraverse.scala +++ b/core/src/main/scala/cats/syntax/bitraverse.scala @@ -2,21 +2,21 @@ package cats package syntax trait BitraverseSyntax extends BitraverseSyntax1 { - implicit def catsSyntaxBitraverse[F[_, _]: Bitraverse, A, B](fab: F[A, B]): BitraverseOps[F, A, B] = + implicit final def catsSyntaxBitraverse[F[_, _]: Bitraverse, A, B](fab: F[A, B]): BitraverseOps[F, A, B] = new BitraverseOps[F, A, B](fab) } private[syntax] trait BitraverseSyntax1 { - implicit def catsSyntaxNestedBitraverse[F[_, _]: Bitraverse, G[_], A, B](fgagb: F[G[A], G[B]]): NestedBitraverseOps[F, G, A, B] = + implicit final def catsSyntaxNestedBitraverse[F[_, _]: Bitraverse, G[_], A, B](fgagb: F[G[A], G[B]]): NestedBitraverseOps[F, G, A, B] = new NestedBitraverseOps[F, G, A, B](fgagb) } -final class BitraverseOps[F[_, _], A, B](fab: F[A, B])(implicit F: Bitraverse[F]) { - def bitraverse[G[_]: Applicative, C, D](f: A => G[C], g: B => G[D]): G[F[C, D]] = +final class BitraverseOps[F[_, _], A, B](val fab: F[A, B]) extends AnyVal { + def bitraverse[G[_]: Applicative, C, D](f: A => G[C], g: B => G[D])(implicit F: Bitraverse[F]): G[F[C, D]] = F.bitraverse(fab)(f, g) } -final class NestedBitraverseOps[F[_, _], G[_], A, B](fgagb: F[G[A], G[B]])(implicit F: Bitraverse[F]) { - def bisequence(implicit G: Applicative[G]): G[F[A, B]] = +final class NestedBitraverseOps[F[_, _], G[_], A, B](val fgagb: F[G[A], G[B]]) extends AnyVal { + def bisequence(implicit F: Bitraverse[F], G: Applicative[G]): G[F[A, B]] = F.bisequence(fgagb) } diff --git a/core/src/main/scala/cats/syntax/cartesian.scala b/core/src/main/scala/cats/syntax/cartesian.scala index 64ce35084a..efff7b4396 100644 --- a/core/src/main/scala/cats/syntax/cartesian.scala +++ b/core/src/main/scala/cats/syntax/cartesian.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait CartesianSyntax1 { - implicit def catsSyntaxUCartesian[FA](fa: FA)(implicit U: Unapply[Cartesian, FA]): CartesianOps[U.M, U.A] = + implicit final def catsSyntaxUCartesian[FA](fa: FA)(implicit U: Unapply[Cartesian, FA]): CartesianOps[U.M, U.A] = new CartesianOps[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC @@ -10,7 +10,7 @@ private[syntax] trait CartesianSyntax1 { } trait CartesianSyntax extends CartesianSyntax1 { - implicit def catsSyntaxCartesian[F[_], A](fa: F[A])(implicit F: Cartesian[F]): CartesianOps[F, A] = + implicit final def catsSyntaxCartesian[F[_], A](fa: F[A])(implicit F: Cartesian[F]): CartesianOps[F, A] = new CartesianOps[F, A] { val self = fa val typeClassInstance = F @@ -18,11 +18,13 @@ trait CartesianSyntax extends CartesianSyntax1 { } abstract class CartesianOps[F[_], A] extends Cartesian.Ops[F, A] { - def |@|[B](fb: F[B]): CartesianBuilder[F]#CartesianBuilder2[A, B] = + final def |@|[B](fb: F[B]): CartesianBuilder[F]#CartesianBuilder2[A, B] = new CartesianBuilder[F] |@| self |@| fb - def *>[B](fb: F[B])(implicit F: Functor[F]): F[B] = F.map(typeClassInstance.product(self, fb)) { case (a, b) => b } + final def *>[B](fb: F[B])(implicit F: Functor[F]): F[B] = + F.map(typeClassInstance.product(self, fb)) { case (_, b) => b } - def <*[B](fb: F[B])(implicit F: Functor[F]): F[A] = F.map(typeClassInstance.product(self, fb)) { case (a, b) => a } + final def <*[B](fb: F[B])(implicit F: Functor[F]): F[A] = + F.map(typeClassInstance.product(self, fb)) { case (a, _) => a } } diff --git a/core/src/main/scala/cats/syntax/coflatMap.scala b/core/src/main/scala/cats/syntax/coflatMap.scala index e63612cc78..e394677da4 100644 --- a/core/src/main/scala/cats/syntax/coflatMap.scala +++ b/core/src/main/scala/cats/syntax/coflatMap.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait CoflatMapSyntax1 { - implicit def catsSyntaxUCoflatMap[FA](fa: FA)(implicit U: Unapply[CoflatMap, FA]): CoflatMap.Ops[U.M, U.A] = new CoflatMap.Ops[U.M, U.A] { + implicit final def catsSyntaxUCoflatMap[FA](fa: FA)(implicit U: Unapply[CoflatMap, FA]): CoflatMap.Ops[U.M, U.A] = new CoflatMap.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC } diff --git a/core/src/main/scala/cats/syntax/comonad.scala b/core/src/main/scala/cats/syntax/comonad.scala index 95dcdeb47a..cbeaf7bb0f 100644 --- a/core/src/main/scala/cats/syntax/comonad.scala +++ b/core/src/main/scala/cats/syntax/comonad.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait ComonadSyntax1 { - implicit def catsSyntaxUComonad[FA](fa: FA)(implicit U: Unapply[Comonad, FA]): Comonad.Ops[U.M, U.A] = + implicit final def catsSyntaxUComonad[FA](fa: FA)(implicit U: Unapply[Comonad, FA]): Comonad.Ops[U.M, U.A] = new Comonad.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/contravariant.scala b/core/src/main/scala/cats/syntax/contravariant.scala index 9cabd49807..7eda421d6b 100644 --- a/core/src/main/scala/cats/syntax/contravariant.scala +++ b/core/src/main/scala/cats/syntax/contravariant.scala @@ -4,7 +4,7 @@ package syntax import cats.functor.Contravariant private[syntax] trait ContravariantSyntax1 { - implicit def catsSyntaxUContravariant[FA](fa: FA)(implicit U: Unapply[Contravariant, FA]): Contravariant.Ops[U.M, U.A] = + implicit final def catsSyntaxUContravariant[FA](fa: FA)(implicit U: Unapply[Contravariant, FA]): Contravariant.Ops[U.M, U.A] = new Contravariant.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/either.scala b/core/src/main/scala/cats/syntax/either.scala index 906ba49f2b..740a9f6558 100644 --- a/core/src/main/scala/cats/syntax/either.scala +++ b/core/src/main/scala/cats/syntax/either.scala @@ -6,15 +6,15 @@ import scala.reflect.ClassTag import scala.util.{Failure, Success, Try} trait EitherSyntax { - implicit def catsSyntaxEither[A, B](eab: Either[A, B]): EitherOps[A, B] = new EitherOps(eab) + implicit final def catsSyntaxEither[A, B](eab: Either[A, B]): EitherOps[A, B] = new EitherOps(eab) - implicit def catsSyntaxEitherObject(either: Either.type): EitherObjectOps = new EitherObjectOps(either) // scalastyle:off ensure.single.space.after.token + implicit final def catsSyntaxEitherObject(either: Either.type): EitherObjectOps = new EitherObjectOps(either) // scalastyle:off ensure.single.space.after.token - implicit def catsSyntaxLeft[A, B](left: Left[A, B]): LeftOps[A, B] = new LeftOps(left) + implicit final def catsSyntaxLeft[A, B](left: Left[A, B]): LeftOps[A, B] = new LeftOps(left) - implicit def catsSyntaxRight[A, B](right: Right[A, B]): RightOps[A, B] = new RightOps(right) + implicit final def catsSyntaxRight[A, B](right: Right[A, B]): RightOps[A, B] = new RightOps(right) - implicit def catsSyntaxEitherId[A](a: A): EitherIdOps[A] = new EitherIdOps(a) + implicit final def catsSyntaxEitherId[A](a: A): EitherIdOps[A] = new EitherIdOps(a) } final class EitherOps[A, B](val eab: Either[A, B]) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/eitherK.scala b/core/src/main/scala/cats/syntax/eitherK.scala index 574b18b5c6..d9f3f0ecb8 100644 --- a/core/src/main/scala/cats/syntax/eitherK.scala +++ b/core/src/main/scala/cats/syntax/eitherK.scala @@ -4,7 +4,7 @@ package syntax import cats.data.EitherK trait EitherKSyntax { - implicit def catsSyntaxEitherK[F[_], A](a: F[A]): EitherKOps[F, A] = new EitherKOps(a) + implicit final def catsSyntaxEitherK[F[_], A](a: F[A]): EitherKOps[F, A] = new EitherKOps(a) } final class EitherKOps[F[_], A](val fa: F[A]) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/eq.scala b/core/src/main/scala/cats/syntax/eq.scala index 87250f8643..3737e95d89 100644 --- a/core/src/main/scala/cats/syntax/eq.scala +++ b/core/src/main/scala/cats/syntax/eq.scala @@ -4,6 +4,7 @@ package syntax import cats.macros.Ops trait EqSyntax { + /** not final so it can be disabled in favor of scalactic equality in tests */ implicit def catsSyntaxEq[A: Eq](a: A): EqOps[A] = new EqOps[A](a) } diff --git a/core/src/main/scala/cats/syntax/flatMap.scala b/core/src/main/scala/cats/syntax/flatMap.scala index 1723dddf83..596019e860 100644 --- a/core/src/main/scala/cats/syntax/flatMap.scala +++ b/core/src/main/scala/cats/syntax/flatMap.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait FlatMapSyntax1 { - implicit def catsSyntaxUFlatMap[FA](fa: FA)(implicit U: Unapply[FlatMap, FA]): FlatMap.Ops[U.M, U.A] = + implicit final def catsSyntaxUFlatMap[FA](fa: FA)(implicit U: Unapply[FlatMap, FA]): FlatMap.Ops[U.M, U.A] = new FlatMap.Ops[U.M, U.A]{ val self = U.subst(fa) val typeClassInstance = U.TC @@ -11,14 +11,14 @@ private[syntax] trait FlatMapSyntax1 { trait FlatMapSyntax extends FlatMap.ToFlatMapOps with FlatMapSyntax1 { - implicit def catsSyntaxFlatten[F[_]: FlatMap, A](ffa: F[F[A]]): FlattenOps[F, A] = + implicit final def catsSyntaxFlatten[F[_]: FlatMap, A](ffa: F[F[A]]): FlattenOps[F, A] = new FlattenOps[F, A](ffa) - implicit def catsSyntaxIfM[F[_]: FlatMap](fa: F[Boolean]): IfMOps[F] = + implicit final def catsSyntaxIfM[F[_]: FlatMap](fa: F[Boolean]): IfMOps[F] = new IfMOps[F](fa) } -final class FlattenOps[F[_], A](ffa: F[F[A]])(implicit F: FlatMap[F]) { +final class FlattenOps[F[_], A](val ffa: F[F[A]]) extends AnyVal { /** * Flatten nested `F` values. @@ -32,10 +32,10 @@ final class FlattenOps[F[_], A](ffa: F[F[A]])(implicit F: FlatMap[F]) { * res0: ErrorOr[Int] = Right(3) * }}} */ - def flatten: F[A] = F.flatten(ffa) + def flatten(implicit F: FlatMap[F]): F[A] = F.flatten(ffa) } -final class IfMOps[F[_]](fa: F[Boolean])(implicit F: FlatMap[F]) { +final class IfMOps[F[_]](val fa: F[Boolean]) extends AnyVal { /** * A conditional lifted into the `F` context. @@ -56,5 +56,5 @@ final class IfMOps[F[_]](fa: F[Boolean])(implicit F: FlatMap[F]) { * res1: Int = 0 * }}} */ - def ifM[B](ifTrue: => F[B], ifFalse: => F[B]): F[B] = F.ifM(fa)(ifTrue, ifFalse) + def ifM[B](ifTrue: => F[B], ifFalse: => F[B])(implicit F: FlatMap[F]): F[B] = F.ifM(fa)(ifTrue, ifFalse) } diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 67589a6f58..9a765f08f0 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait FoldableSyntax1 { - implicit def catsSyntaxUFoldable[FA](fa: FA)(implicit U: Unapply[Foldable, FA]): Foldable.Ops[U.M, U.A] = + implicit final def catsSyntaxUFoldable[FA](fa: FA)(implicit U: Unapply[Foldable, FA]): Foldable.Ops[U.M, U.A] = new Foldable.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC @@ -10,12 +10,12 @@ private[syntax] trait FoldableSyntax1 { } trait FoldableSyntax extends Foldable.ToFoldableOps with FoldableSyntax1 { - implicit def catsSyntaxNestedFoldable[F[_]: Foldable, G[_], A](fga: F[G[A]]): NestedFoldableOps[F, G, A] = + implicit final def catsSyntaxNestedFoldable[F[_]: Foldable, G[_], A](fga: F[G[A]]): NestedFoldableOps[F, G, A] = new NestedFoldableOps[F, G, A](fga) } -final class NestedFoldableOps[F[_], G[_], A](fga: F[G[A]])(implicit F: Foldable[F]) { - def sequence_(implicit G: Applicative[G]): G[Unit] = F.sequence_(fga) +final class NestedFoldableOps[F[_], G[_], A](val fga: F[G[A]]) extends AnyVal { + def sequence_(implicit F: Foldable[F], G: Applicative[G]): G[Unit] = F.sequence_(fga) /** * @see [[Foldable.foldK]]. @@ -29,5 +29,5 @@ final class NestedFoldableOps[F[_], G[_], A](fga: F[G[A]])(implicit F: Foldable[ * res0: Set[Int] = Set(1, 2, 3, 4) * }}} */ - def foldK(implicit G: MonoidK[G]): G[A] = F.foldK(fga) + def foldK(implicit F: Foldable[F], G: MonoidK[G]): G[A] = F.foldK(fga) } diff --git a/core/src/main/scala/cats/syntax/functor.scala b/core/src/main/scala/cats/syntax/functor.scala index ba8be22cbd..478299c92a 100644 --- a/core/src/main/scala/cats/syntax/functor.scala +++ b/core/src/main/scala/cats/syntax/functor.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait FunctorSyntax1 { - implicit def catsSyntaxUFunctor[FA](fa: FA)(implicit U: Unapply[Functor, FA]): Functor.Ops[U.M, U.A] = + implicit final def catsSyntaxUFunctor[FA](fa: FA)(implicit U: Unapply[Functor, FA]): Functor.Ops[U.M, U.A] = new Functor.Ops[U.M, U.A]{ val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/functorFilter.scala b/core/src/main/scala/cats/syntax/functorFilter.scala index eb7757bee5..dfefedcce9 100644 --- a/core/src/main/scala/cats/syntax/functorFilter.scala +++ b/core/src/main/scala/cats/syntax/functorFilter.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait FunctorFilterSyntax1 { - implicit def catsSyntaxUFunctorFilter[FA](fa: FA)(implicit U: Unapply[FunctorFilter, FA]): FunctorFilter.Ops[U.M, U.A] = + implicit final def catsSyntaxUFunctorFilter[FA](fa: FA)(implicit U: Unapply[FunctorFilter, FA]): FunctorFilter.Ops[U.M, U.A] = new FunctorFilter.Ops[U.M, U.A]{ val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/group.scala b/core/src/main/scala/cats/syntax/group.scala index dca6c12780..01d29cf3ae 100644 --- a/core/src/main/scala/cats/syntax/group.scala +++ b/core/src/main/scala/cats/syntax/group.scala @@ -5,7 +5,7 @@ import cats.macros.Ops trait GroupSyntax extends SemigroupSyntax { // TODO: use simulacrum instances eventually - implicit def catsSyntaxGroup[A: Group](a: A): GroupOps[A] = + implicit final def catsSyntaxGroup[A: Group](a: A): GroupOps[A] = new GroupOps[A](a) } diff --git a/core/src/main/scala/cats/syntax/invariant.scala b/core/src/main/scala/cats/syntax/invariant.scala index 6271cc8077..3f425c002c 100644 --- a/core/src/main/scala/cats/syntax/invariant.scala +++ b/core/src/main/scala/cats/syntax/invariant.scala @@ -4,7 +4,7 @@ package syntax import cats.functor.Invariant private[syntax] trait InvariantSyntax1 { - implicit def catsSyntaxUInvariant[FA](fa: FA)(implicit U: Unapply[Invariant, FA]): Invariant.Ops[U.M, U.A] = + implicit final def catsSyntaxUInvariant[FA](fa: FA)(implicit U: Unapply[Invariant, FA]): Invariant.Ops[U.M, U.A] = new Invariant.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/ior.scala b/core/src/main/scala/cats/syntax/ior.scala index bc8bdfacba..41ab0bca1b 100644 --- a/core/src/main/scala/cats/syntax/ior.scala +++ b/core/src/main/scala/cats/syntax/ior.scala @@ -3,7 +3,7 @@ package cats.syntax import cats.data.Ior trait IorSyntax { - implicit def catsSyntaxIorId[A](a: A): IorIdOps[A] = new IorIdOps(a) + implicit final def catsSyntaxIorId[A](a: A): IorIdOps[A] = new IorIdOps(a) } final class IorIdOps[A](val a: A) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/list.scala b/core/src/main/scala/cats/syntax/list.scala index 7079dbfad4..d354eb7c7c 100644 --- a/core/src/main/scala/cats/syntax/list.scala +++ b/core/src/main/scala/cats/syntax/list.scala @@ -4,7 +4,7 @@ package syntax import cats.data.NonEmptyList trait ListSyntax { - implicit def catsSyntaxList[A](la: List[A]): ListOps[A] = new ListOps(la) + implicit final def catsSyntaxList[A](la: List[A]): ListOps[A] = new ListOps(la) } final class ListOps[A](val la: List[A]) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/monad.scala b/core/src/main/scala/cats/syntax/monad.scala index 0dcc5f1b6c..2772c5a8ed 100644 --- a/core/src/main/scala/cats/syntax/monad.scala +++ b/core/src/main/scala/cats/syntax/monad.scala @@ -2,14 +2,14 @@ package cats package syntax trait MonadSyntax { - implicit def catsSyntaxMonad[F[_]: Monad, A](fa: F[A]): MonadOps[F, A] = new MonadOps(fa) + implicit final def catsSyntaxMonad[F[_], A](fa: F[A]): MonadOps[F, A] = new MonadOps(fa) } -final class MonadOps[F[_], A](fa: F[A])(implicit M: Monad[F]) { - def whileM[G[_]](p: F[Boolean])(implicit G: Alternative[G]): F[G[A]] = M.whileM(p)(fa) - def whileM_(p: F[Boolean]): F[Unit] = M.whileM_(p)(fa) - def untilM[G[_]](p: F[Boolean])(implicit G: Alternative[G]): F[G[A]] = M.untilM(fa)(p) - def untilM_(p: F[Boolean]): F[Unit] = M.untilM_(fa)(p) - def iterateWhile(p: A => Boolean): F[A] = M.iterateWhile(fa)(p) - def iterateUntil(p: A => Boolean): F[A] = M.iterateUntil(fa)(p) +final class MonadOps[F[_], A](val fa: F[A]) extends AnyVal { + def whileM[G[_]](p: F[Boolean])(implicit M: Monad[F], G: Alternative[G]): F[G[A]] = M.whileM(p)(fa) + def whileM_(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.whileM_(p)(fa) + def untilM[G[_]](p: F[Boolean])(implicit M: Monad[F], G: Alternative[G]): F[G[A]] = M.untilM(fa)(p) + def untilM_(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.untilM_(fa)(p) + def iterateWhile(p: A => Boolean)(implicit M: Monad[F]): F[A] = M.iterateWhile(fa)(p) + def iterateUntil(p: A => Boolean)(implicit M: Monad[F]): F[A] = M.iterateUntil(fa)(p) } diff --git a/core/src/main/scala/cats/syntax/monadCombine.scala b/core/src/main/scala/cats/syntax/monadCombine.scala index 40e53f2449..f970cf6b9b 100644 --- a/core/src/main/scala/cats/syntax/monadCombine.scala +++ b/core/src/main/scala/cats/syntax/monadCombine.scala @@ -3,14 +3,14 @@ package syntax trait MonadCombineSyntax { // TODO: use simulacrum instances eventually - implicit def catsSyntaxMonadCombine[F[_]: MonadCombine, G[_], A](fga: F[G[A]]): MonadCombineOps[F, G, A] = + implicit final def catsSyntaxMonadCombine[F[_]: MonadCombine, G[_], A](fga: F[G[A]]): MonadCombineOps[F, G, A] = new MonadCombineOps[F, G, A](fga) - implicit def catsSyntaxMonadCombineSeparate[F[_]: MonadCombine, G[_, _], A, B](fgab: F[G[A, B]]): SeparateOps[F, G, A, B] = + implicit final def catsSyntaxMonadCombineSeparate[F[_]: MonadCombine, G[_, _], A, B](fgab: F[G[A, B]]): SeparateOps[F, G, A, B] = new SeparateOps[F, G, A, B](fgab) } -final class MonadCombineOps[F[_], G[_], A](fga: F[G[A]])(implicit F: MonadCombine[F]) { +final class MonadCombineOps[F[_], G[_], A](val fga: F[G[A]]) extends AnyVal { /** * @see [[MonadCombine.unite]] @@ -23,10 +23,10 @@ final class MonadCombineOps[F[_], G[_], A](fga: F[G[A]])(implicit F: MonadCombin * res0: List[Int] = List(1, 2, 3, 4) * }}} */ - def unite(implicit G: Foldable[G]): F[A] = F.unite(fga) + def unite(implicit F: MonadCombine[F], G: Foldable[G]): F[A] = F.unite(fga) } -final class SeparateOps[F[_], G[_, _], A, B](fgab: F[G[A, B]])(implicit F: MonadCombine[F]) { +final class SeparateOps[F[_], G[_, _], A, B](val fgab: F[G[A, B]]) extends AnyVal { /** * @see [[MonadCombine.separate]] @@ -39,5 +39,5 @@ final class SeparateOps[F[_], G[_, _], A, B](fgab: F[G[A, B]])(implicit F: Monad * res0: (List[String], List[Int]) = (List(error),List(1)) * }}} */ - def separate(implicit G: Bifoldable[G]): (F[A], F[B]) = F.separate(fgab) + def separate(implicit F: MonadCombine[F], G: Bifoldable[G]): (F[A], F[B]) = F.separate(fgab) } diff --git a/core/src/main/scala/cats/syntax/monadError.scala b/core/src/main/scala/cats/syntax/monadError.scala index 8d0bf677a1..8ea1d590d1 100644 --- a/core/src/main/scala/cats/syntax/monadError.scala +++ b/core/src/main/scala/cats/syntax/monadError.scala @@ -2,11 +2,11 @@ package cats package syntax trait MonadErrorSyntax { - implicit def catsSyntaxMonadError[F[_], E, A](fa: F[A])(implicit F: MonadError[F, E]): MonadErrorOps[F, E, A] = + implicit final def catsSyntaxMonadError[F[_], E, A](fa: F[A])(implicit F: MonadError[F, E]): MonadErrorOps[F, E, A] = new MonadErrorOps(fa) } -final class MonadErrorOps[F[_], E, A](fa: F[A])(implicit F: MonadError[F, E]) { - def ensure(error: => E)(predicate: A => Boolean): F[A] = +final class MonadErrorOps[F[_], E, A](val fa: F[A]) extends AnyVal { + def ensure(error: => E)(predicate: A => Boolean)(implicit F: MonadError[F, E]): F[A] = F.ensure(fa)(error)(predicate) } diff --git a/core/src/main/scala/cats/syntax/monadFilter.scala b/core/src/main/scala/cats/syntax/monadFilter.scala index 21c98a869b..8413fb64f5 100644 --- a/core/src/main/scala/cats/syntax/monadFilter.scala +++ b/core/src/main/scala/cats/syntax/monadFilter.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait MonadFilterSyntax1 { - implicit def catsSyntaxUMonadFilter[FA](fa: FA)(implicit U: Unapply[MonadFilter, FA]): MonadFilter.Ops[U.M, U.A] = + implicit final def catsSyntaxUMonadFilter[FA](fa: FA)(implicit U: Unapply[MonadFilter, FA]): MonadFilter.Ops[U.M, U.A] = new MonadFilter.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/monoid.scala b/core/src/main/scala/cats/syntax/monoid.scala index 0858424a04..dcbf0fd680 100644 --- a/core/src/main/scala/cats/syntax/monoid.scala +++ b/core/src/main/scala/cats/syntax/monoid.scala @@ -3,10 +3,10 @@ package syntax trait MonoidSyntax extends SemigroupSyntax { // TODO: use simulacrum instances eventually - implicit def catsSyntaxMonoid[A: Monoid](a: A): MonoidOps[A] = + implicit final def catsSyntaxMonoid[A: Monoid](a: A): MonoidOps[A] = new MonoidOps[A](a) } -final class MonoidOps[A: Monoid](lhs: A) { - def isEmpty(implicit eq: Eq[A]): Boolean = Monoid[A].isEmpty(lhs)(eq) +final class MonoidOps[A](val lhs: A) extends AnyVal { + def isEmpty(implicit A: Monoid[A], eq: Eq[A]): Boolean = A.isEmpty(lhs)(eq) } diff --git a/core/src/main/scala/cats/syntax/order.scala b/core/src/main/scala/cats/syntax/order.scala index e5c14bfe4d..36c33386a3 100644 --- a/core/src/main/scala/cats/syntax/order.scala +++ b/core/src/main/scala/cats/syntax/order.scala @@ -5,7 +5,7 @@ import cats.macros.Ops import cats.kernel.Comparison trait OrderSyntax extends PartialOrderSyntax { - implicit def catsSyntaxOrder[A: Order](a: A): OrderOps[A] = + implicit final def catsSyntaxOrder[A: Order](a: A): OrderOps[A] = new OrderOps[A](a) } diff --git a/core/src/main/scala/cats/syntax/partialOrder.scala b/core/src/main/scala/cats/syntax/partialOrder.scala index 21b350f732..3e5d2e0489 100644 --- a/core/src/main/scala/cats/syntax/partialOrder.scala +++ b/core/src/main/scala/cats/syntax/partialOrder.scala @@ -4,7 +4,7 @@ package syntax import cats.macros.Ops trait PartialOrderSyntax extends EqSyntax { - implicit def catsSyntaxPartialOrder[A: PartialOrder](a: A): PartialOrderOps[A] = + implicit final def catsSyntaxPartialOrder[A: PartialOrder](a: A): PartialOrderOps[A] = new PartialOrderOps[A](a) } diff --git a/core/src/main/scala/cats/syntax/reducible.scala b/core/src/main/scala/cats/syntax/reducible.scala index 8d5b89f80c..a513d88415 100644 --- a/core/src/main/scala/cats/syntax/reducible.scala +++ b/core/src/main/scala/cats/syntax/reducible.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait ReducibleSyntax1 { - implicit def catsSyntaxUReducible[FA](fa: FA)(implicit U: Unapply[Reducible, FA]): Reducible.Ops[U.M, U.A] = + implicit final def catsSyntaxUReducible[FA](fa: FA)(implicit U: Unapply[Reducible, FA]): Reducible.Ops[U.M, U.A] = new Reducible.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC @@ -10,10 +10,10 @@ private[syntax] trait ReducibleSyntax1 { } trait ReducibleSyntax extends Reducible.ToReducibleOps with ReducibleSyntax1 { - implicit def catsSyntaxNestedReducible[F[_]: Reducible, G[_], A](fga: F[G[A]]): NestedReducibleOps[F, G, A] = + implicit final def catsSyntaxNestedReducible[F[_]: Reducible, G[_], A](fga: F[G[A]]): NestedReducibleOps[F, G, A] = new NestedReducibleOps[F, G, A](fga) } -final class NestedReducibleOps[F[_], G[_], A](fga: F[G[A]])(implicit F: Reducible[F]) { - def reduceK(implicit G: SemigroupK[G]): G[A] = F.reduceK(fga) +final class NestedReducibleOps[F[_], G[_], A](val fga: F[G[A]]) extends AnyVal { + def reduceK(implicit F: Reducible[F], G: SemigroupK[G]): G[A] = F.reduceK(fga) } diff --git a/core/src/main/scala/cats/syntax/semigroup.scala b/core/src/main/scala/cats/syntax/semigroup.scala index b87cfce3ba..54338b7ff0 100644 --- a/core/src/main/scala/cats/syntax/semigroup.scala +++ b/core/src/main/scala/cats/syntax/semigroup.scala @@ -5,7 +5,7 @@ import cats.macros.Ops trait SemigroupSyntax { // TODO: use simulacrum instances eventually - implicit def catsSyntaxSemigroup[A: Semigroup](a: A): SemigroupOps[A] = + implicit final def catsSyntaxSemigroup[A: Semigroup](a: A): SemigroupOps[A] = new SemigroupOps[A](a) } diff --git a/core/src/main/scala/cats/syntax/semigroupk.scala b/core/src/main/scala/cats/syntax/semigroupk.scala index b9e788404c..39f05b546d 100644 --- a/core/src/main/scala/cats/syntax/semigroupk.scala +++ b/core/src/main/scala/cats/syntax/semigroupk.scala @@ -3,7 +3,7 @@ package syntax private[syntax] trait SemigroupKSyntax1 { // TODO: use simulacrum instances eventually - implicit def catsSyntaxUSemigroup[FA](fa: FA)(implicit U: Unapply[SemigroupK, FA]): SemigroupK.Ops[U.M, U.A] = + implicit final def catsSyntaxUSemigroup[FA](fa: FA)(implicit U: Unapply[SemigroupK, FA]): SemigroupK.Ops[U.M, U.A] = new SemigroupK.Ops[U.M, U.A] { val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/show.scala b/core/src/main/scala/cats/syntax/show.scala index c66b6b8853..45e94fe15d 100644 --- a/core/src/main/scala/cats/syntax/show.scala +++ b/core/src/main/scala/cats/syntax/show.scala @@ -2,5 +2,5 @@ package cats package syntax trait ShowSyntax extends Show.ToShowOps { - implicit def showInterpolator(sc: StringContext): Show.ShowInterpolator = Show.ShowInterpolator(sc) + implicit final def showInterpolator(sc: StringContext): Show.ShowInterpolator = Show.ShowInterpolator(sc) } diff --git a/core/src/main/scala/cats/syntax/transLift.scala b/core/src/main/scala/cats/syntax/transLift.scala index d985503506..f85ed47835 100644 --- a/core/src/main/scala/cats/syntax/transLift.scala +++ b/core/src/main/scala/cats/syntax/transLift.scala @@ -2,7 +2,8 @@ package cats package syntax trait TransLiftSyntax { - implicit def catsSyntaxTransLift[E](ma: E)(implicit U: Unapply[Trivial.PH1, E]): TransLiftOps[U.M, U.A] = new TransLiftOps(U.subst(ma)) + implicit final def catsSyntaxTransLift[E](ma: E)(implicit U: Unapply[Trivial.PH1, E]): TransLiftOps[U.M, U.A] = + new TransLiftOps(U.subst(ma)) } final class TransLiftOps[M0[_], A](val ma: M0[A]) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/traverse.scala b/core/src/main/scala/cats/syntax/traverse.scala index d578b4dbcc..f004d7ba98 100644 --- a/core/src/main/scala/cats/syntax/traverse.scala +++ b/core/src/main/scala/cats/syntax/traverse.scala @@ -2,7 +2,7 @@ package cats package syntax private[syntax] trait TraverseSyntax1 { - implicit def catsSyntaxUTraverse[FA](fa: FA)(implicit U: Unapply[Traverse, FA]): Traverse.Ops[U.M, U.A] = + implicit final def catsSyntaxUTraverse[FA](fa: FA)(implicit U: Unapply[Traverse, FA]): Traverse.Ops[U.M, U.A] = new Traverse.Ops[U.M, U.A]{ val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/traverseFilter.scala b/core/src/main/scala/cats/syntax/traverseFilter.scala index 4317db2929..6b24109251 100644 --- a/core/src/main/scala/cats/syntax/traverseFilter.scala +++ b/core/src/main/scala/cats/syntax/traverseFilter.scala @@ -4,7 +4,7 @@ package syntax trait TraverseFilterSyntax extends TraverseFilter.ToTraverseFilterOps with TraverseFilterSyntax1 private[syntax] trait TraverseFilterSyntax1 { - implicit def catsSyntaxUTraverseFilter[FA](fa: FA)(implicit U: Unapply[TraverseFilter, FA]): TraverseFilter.Ops[U.M, U.A] = + implicit final def catsSyntaxUTraverseFilter[FA](fa: FA)(implicit U: Unapply[TraverseFilter, FA]): TraverseFilter.Ops[U.M, U.A] = new TraverseFilter.Ops[U.M, U.A]{ val self = U.subst(fa) val typeClassInstance = U.TC diff --git a/core/src/main/scala/cats/syntax/validated.scala b/core/src/main/scala/cats/syntax/validated.scala index 11e6972a42..3b7ae5c8ad 100644 --- a/core/src/main/scala/cats/syntax/validated.scala +++ b/core/src/main/scala/cats/syntax/validated.scala @@ -4,7 +4,7 @@ package syntax import cats.data.{ Validated, ValidatedNel } trait ValidatedSyntax { - implicit def catsSyntaxValidatedId[A](a: A): ValidatedIdSyntax[A] = new ValidatedIdSyntax(a) + implicit final def catsSyntaxValidatedId[A](a: A): ValidatedIdSyntax[A] = new ValidatedIdSyntax(a) } final class ValidatedIdSyntax[A](val a: A) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/vector.scala b/core/src/main/scala/cats/syntax/vector.scala index 64b8fe2f68..213c221ccf 100644 --- a/core/src/main/scala/cats/syntax/vector.scala +++ b/core/src/main/scala/cats/syntax/vector.scala @@ -3,7 +3,7 @@ package cats.syntax import cats.data.NonEmptyVector trait VectorSyntax { - implicit def catsSyntaxVectors[A](va: Vector[A]): VectorOps[A] = new VectorOps(va) + implicit final def catsSyntaxVectors[A](va: Vector[A]): VectorOps[A] = new VectorOps(va) } final class VectorOps[A](val va: Vector[A]) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/writer.scala b/core/src/main/scala/cats/syntax/writer.scala index 828592e6d2..31b36c66dd 100644 --- a/core/src/main/scala/cats/syntax/writer.scala +++ b/core/src/main/scala/cats/syntax/writer.scala @@ -4,7 +4,7 @@ package syntax import cats.data.Writer trait WriterSyntax { - implicit def catsSyntaxWriterId[A](a: A): WriterIdSyntax[A] = new WriterIdSyntax(a) + implicit final def catsSyntaxWriterId[A](a: A): WriterIdSyntax[A] = new WriterIdSyntax(a) } final class WriterIdSyntax[A](val a: A) extends AnyVal { diff --git a/docs/src/main/tut/guidelines.md b/docs/src/main/tut/guidelines.md new file mode 100644 index 0000000000..2a8f1a8d87 --- /dev/null +++ b/docs/src/main/tut/guidelines.md @@ -0,0 +1,27 @@ +--- +layout: page +title: "Guidelines" +section: "guidelines" +position: 7 +--- + +# Guidelines + +All guidelines in cats should have clear justifications. There is no room for tribal wisdom in a simple library. + +## Syntax + +### Composing Implicit Conversions in Traits + +Implicit syntax conversions provided in publicly-exposed traits should be marked final +so that any composition of the traits provides conversions that can all be inlined. + +### Ops Classes + +Ops classes should be marked final and extend AnyVal, to take full advantage of inlining and prevent unnecessary allocations. + +The most notable exception is the case where all of the ops in the class are provided by zero-cost macros anyway, +for example with Simulacrum. + +#### TODO: +Once we drop 2.10 support, AnyVal-extending class constructor parameters can be marked as private. \ No newline at end of file