-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
alleycats - Extract[F[_]] the only way to get the syntax is the deprecated one #4670
base: main
Are you sure you want to change the base?
alleycats - Extract[F[_]] the only way to get the syntax is the deprecated one #4670
Conversation
implicit class ExtractOps[F[_], A](fa: F[A])(implicit ev: Extract[F]) { | ||
def extract(): A = ev.extract(fa) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it makes sense to convert it into a value class, e.g.:
implicit class ExtractOps[F[_], A](fa: F[A])(implicit ev: Extract[F]) { | |
def extract(): A = ev.extract(fa) | |
} | |
implicit final class ExtractOps[F[_], A](private val fa: F[A]) extends AnyVal { | |
def extract(implicit ev: Extract[F]): A = ev.extract(fa) | |
} |
The reason why I think it could make sense is that
-
This is a pretty valid use case for value classes in general and allows to save on memory allocations a little bit.
-
Newer syntaxes in Cats-core use this approach a lot, see
Applicative
syntax for example:cats/core/src/main/scala/cats/syntax/applicative.scala
Lines 37 to 56 in 769bf21
final class ApplicativeIdOps[A](private val a: A) extends AnyVal { def pure[F[_]](implicit F: Applicative[F]): F[A] = F.pure(a) } @deprecated("Use by-value or by-name version", "2.8.0") final class ApplicativeOps[F[_], A](private 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) } final class ApplicativeByValueOps[F[_], A](private val fa: F[A]) extends AnyVal { def replicateA(n: Int)(implicit F: Applicative[F]): F[List[A]] = F.replicateA(n, fa) def replicateA_(n: Int)(implicit F: Applicative[F]): F[Unit] = F.replicateA_(n, fa) } final class ApplicativeByNameOps[F[_], A](private val fa: () => F[A]) extends AnyVal { 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()) }
Thank you for the PR! |
Great idea! I would definitely apply that. |
The reason why I think it could make sense is that: 1. This is a pretty valid use case for value classes in general and allows to save on memory allocations a little bit. 2. Newer syntaxes in Cats-core use this approach a lot, see Applicative syntax for example: Co-authored-by: Sergey Torgashov <[email protected]>
The problem here is that the code should be implemented in this way:
Doesn't this break the limitations of using value classes? I mean passing type arguments to |
@aluscent ,
To be honest, I'm not sure I'm totally getting your concern. Why do you think the above should cause the boxing, could you elaborate please? To my best knowledge, no it shouldn't in this case. But I might be missing something. So do not take my word for it :) If you're in doubt, you can check it for yourself by decompiling scala code to java (there are a plenty of open-source tools available) and see what it looks like. I did it a few times for some other typeclasses and |
Fixes #4642