Skip to content
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

Pattern matching Option with strictEquality #10850

Closed
joschua-fink opened this issue Dec 18, 2020 · 6 comments
Closed

Pattern matching Option with strictEquality #10850

joschua-fink opened this issue Dec 18, 2020 · 6 comments

Comments

@joschua-fink
Copy link

Minimized example

val o: Option[Boolean] = Random.nextInt(3) match {
  case 0 => Some(true)
  case 1 => Some(false)
  case 2 => None
} 

o match {
  case Some(true) =>
  case Some(false) =>
  case None =>
}

Output

[error] 22 |      case None =>
[error]    |           ^^^^
[error]    |Values of types object None and Option[Boolean] cannot be compared with == or !=

Expectation

The example does not compile with -language:strictEquality in Scala 3.0.0-M3, because there is no predefined CanEqual for Option according to the documentation. So it is technically not a bug.

To be honest I have not understood multiversal equality completely, yet. But for me it would make sense for this example to compile without providing a CanEqual as user for a Option type which is part of the Scala standard library. It makes also sense for me that something like if Some(true) == None then ??? fails to compile with -language:strictEquality, which it currently does.

@joschua-fink
Copy link
Author

Also on that topic, I would expect case classes to automatically derive a CanEqual as long as all fields have a CanEqual. E.g.

// does not compile, but should in my opinion
case class A(v: Boolean)
A(true) == A(true)

// does compile
case class A(v: Boolean) derives CanEqual
A(true) == A(true)

@LPTK
Copy link
Contributor

LPTK commented Dec 18, 2020

This is so annoying. I've hit it many times, and it basically makes strictEquality unusable as it is.

It's arguably a bug, because a type test with the object's singleton type does work, and compiles fine:

o match {
  case Some(true) =>
  case Some(false) =>
  case _: None.type =>
}

AFAIK this compiles to the same thing, and has the same semantics.

So CanEqual should never be required for singletons which can be type-pattern-matched.

@sjrd
Copy link
Member

sjrd commented Dec 18, 2020

AFAIK this compiles to the same thing, and has the same semantics.

So CanEqual should never be required for singletons which can be type-pattern-matched.

They're not the same:

scala> val x: Seq[Int] = Vector()
val x: Seq[Int] = Vector()

scala> x match { case Nil => "yup"; case _ => "nope" }
val res0: String = yup

scala> x match { case _: Nil.type => "yup"; case _ => "nope" }
val res1: String = nope

case Obj => performs Obj == x; whereas cast _: Obj.type => performs Obj eq x.

@LPTK
Copy link
Contributor

LPTK commented Dec 18, 2020

Ah yeah, I was misremembering #9359 (eq is indeed used, but only when there is a visible AnyRef bound on the singleton – otherwise it uses ==).

Still, I think CanEqual should not be required when a singleton type test works. That seems like a good heuristic.

@odersky
Copy link
Contributor

odersky commented Dec 20, 2020

I don't think I'll find the time to work on this for now. strictEquality has to be seen as experimental and incomplete. It will probably remain so until we get a chance to redesign the standard library.

@kevin-lee
Copy link
Contributor

It should be fixed by #12419 and #13265 and as far as I know, it will be available in Scala 3.1.0.
In the meantime, you can use this. https://github.com/Kevin-Lee/can-equal

@dwijnand dwijnand added this to the 3.1.0 milestone Aug 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants