-
-
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
Make whenA
/unlessA
syntax by-name lazy
#4207
Conversation
This reverts commit 3e8eaba.
Maybe just keep both |
I'm afraid not, see scala/bug#12578 and linked issues for details.
|
Right.. Seems it is not going to be that easy :) object outer {
object syntax extends SyntaxLowLevel {
implicit class Ops2(x: String) { def bar: Int = 2 }
}
trait SyntaxLowLevel {
implicit class Ops1(x: String) {
private[outer] def bar: Int = 1
def car: String = "I'm also here"
}
}
}
object test extends App {
import outer.syntax._
val fooBar = "foo".bar
val fooCar = "foo".car
println(s"$fooBar.$fooCar")
}
https://scastie.scala-lang.org/satorg/Lhe4QuVMRqyaHtg8WRtzwQ/8 |
I mean, I wonder if this trick might be working: trait ApplicativeSyntax extends ApplicativeSyntaxLowerLevel {
implicit final def catsSyntaxApplicativeId[A](a: A): ApplicativeIdOps[A] =
new ApplicativeIdOps[A](a)
implicit final def catsSyntaxApplicativeByName[F[_], A](fa: => F[A]): ApplicativeByNameOps[F, A] =
new ApplicativeByNameOps[F, A](() => fa)
// Need to keep this for the bin-compat purposes I guess.
@deprecated("Use bin-compat version", "2.8.0")
final def catsSyntaxApplicative[F[_], A](fa: F[A]): ApplicativeOps[F, A] =
new ApplicativeOps[F, A](fa)
}
sealed trait ApplicativeSyntaxLowerLevel {
implicit final def catsSyntaxApplicativeBinCompat[F[_], A](fa: F[A]): ApplicativeOps[F, A] =
new ApplicativeOps[F, A](fa)
} ..or something like this. I haven't actually tested it though... |
Huh, interesting. Actually I had tried that prioritization trick too, and it didn't work. But I do see your scastie there 🤔 Edit: I gave it a try in f32fec9 but doesn't seem to work. |
Yes, I see – it does not indeed.. The idea # 3 then – what if we do it in this way: trait ApplicativeSyntax {
implicit final def catsSyntaxApplicativeId[A](a: A): ApplicativeIdOps[A] =
new ApplicativeIdOps[A](a)
// Brand-new implicit solely for by-name params
implicit final def catsSyntaxApplicativeByName[F[_], A](fa: => F[A]): ApplicativeByNameOps[F, A] =
new ApplicativeByNameOps[F, A](() => fa)
// Brand-new implicit entirely for by-value params
implicit final def catsSyntaxApplicativeByValue[F[_], A](fa: F[A]): ApplicativeByValueOps[F, A] =
new ApplicativeByValueOps[F, A](fa)
// as usual – preserved for bin-compat, but not used
@deprecated("Use by-name version", "2.8.0")
final def catsSyntaxApplicative[F[_], A](fa: F[A]): ApplicativeOps[F, A] =
new ApplicativeOps[F, A](fa)
}
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-name version", "2.8.0") // as usual – preserved for bin-compat, not used
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 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())
}
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)
} In this case the by-name and by-value syntax methods are completely separated from each other. |
Ah, yes of course, that should work! Let me fix that, thank you :) |
Co-authored-by: satorg <[email protected]>
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.
Cool, thank you!
Fixes #3687, supersedes #3899.
These changes are based on #3899 but binary and source compatible without introducing any new methods.
Note that
replicateA
also becomes by-name in these changes. This is unnecessary and possibly a minor de-optimization, but I don't see any way around it. Note that the usual package-private tricks don't work well with syntax e.g. see scala/bug#12578.Edit: although, I suppose there's an argument that
replicateA
should be made by-name on the typeclass itself for whenn = 0
, but that's another can of worms :)