Checking for =:=

Hey, does anyone know a workaround to check if at compile time it is known (or not known) that two types are the same?

Eg,

import scala.util.NotGiven

def printIfEqual[
    A <: Singleton,
    B <: Singleton
](a: A, b: B)(using ev: A =:= B | NotGiven[A =:= B]) =
  ev match
    case eq: (A =:= B) =>
      println(s"$a == $b")
    case neq: NotGiven[A =:= B] =>
      println(s"Unknown Equality")
  end match
end printIfEqual

@main
def main() =
  printIfEqual[1, 1](1, 1) // Errors with "Ambiguous given instances"
  printIfEqual[1, 2](1, 2)
end main

Opened Type Union of A and NotGiven[A] is ambiguous but shouldn't · Issue #23065 · scala/scala3 · GitHub but maybe there is a workaround to check =:= (working on something with match types that simplifies code and return type when two type parameters are known to be equal)

I call this the default implicit value trick.
Just use using ev: A =:= B = null

Here is an example: Scastie - An interactive playground for Scala.
You probably can avoid the Option wrapping by simply checking for null.

Do be careful with this trick, especially with equality, since A =:= B is also a A => B function, and the compiler will be happy to apply it when needed. But since we have a default value, this function will always be there, but sometimes will be a null; which means a NPE.

2 Likes

Type matching seems possible with this approach, but will keep in mind null safety :s

type Result[CurrencyCodeA, CurrencyCodeB, E <: CurrencyCodeA =:= CurrencyCodeB] = E match
  case Null => Either[String, Money[CurrencyCodeA]]
  case ev: (CurrencyCodeA =:= CurrencyCodeB) => Money[CurrencyCodeA]