-
-
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
Add Functor.widen #1080
Comments
Out of curiosity, what are the arguments to not make Functor's type parameter covariant? |
I believe the "singleton instance trick is unsafe" article does not apply in this case. The reason for its unsafety is singleton type patterns, however I don't believe they are unsound in this case: class F[+A] // (with implicit functor in scope)
class A
class B extends A
val f: F[B] = ???
val g: F[A] = f.widen
val g2: F[A] = f match {
case _: g.type => f
} As you can see, having Edit: This hinges on the absence of functorial GADTs in cats which violate Liskov lifting. |
Also (sorry for the spam) I plan to tackle this with a PR later today. |
Well, technically it is possible to use this to perform an unsafe cast (tested with b149835): package com.example
import cats.Functor
import cats.data.Const
import cats.std.int._
object Example extends App {
type IntConst[A] = Const[Int, A]
def unsafeCoerce[A, B]: (A => B) = {
val n: IntConst[Nothing] = Const[Int, Nothing](0)
val b: IntConst[B] = Functor[IntConst].widen[Nothing, B](n)
Functor[IntConst].widen[Nothing, A](n) match {
case _: b.type =>
implicitly[A =:= B]
}
}
val d: Double = unsafeCoerce[String, Double]("a")
println(d)
} This produces:
|
@durban yeah, that does bother me a bit. I think it can only be a problem when reference equality is used (this is how |
@ceedubs Yeah, I guess a warning in scaladoc is the least bad thing to do. I agree, that in practice, this probably rarely causes a problem, and can appreciate the efficiency argument. What really bothers me though is that the root cause (if I undestood correctly) is that we're lying to scalac: |
This is a followup on [this discussion](typelevel#1080 (comment)).
@durban I agree that it's unfortunate that I'm going to go ahead and close this out since #1208 was merged. But please feel free to continue this conversation. |
I think that we should have something like
def widen[A, AA >: A](fa: F[A]): F[AA]
on (covariant)Functor
. People who are working in code that is a hybrid of OO and FP (which is pretty much everyone who uses FP in scala, since subtyping is used for sum types) often find themselves wanting something like this.A straightforward implementation is
map identity
, but this solution is often not very performant. Since the functor laws specify thatfa map identity
is equivalent tofa
, there generally shouldn't be any problem with just using anasInstanceOf
cast instead of mapping over identity. I think that The singleton instance trick is unsafe points out that there are ways that you can get unsound results with this approach in certain situations. I'm not sure how much of a real problem that is in practice.The text was updated successfully, but these errors were encountered: