According to the Scala Language Specification,
Two compound types are equivalent if the sequences of their component are pairwise equivalent, and occur in the same order, and their refinements are equivalent. Two refinements are equivalent if they bind the same names and the modifiers, types and bounds of every declared entity are equivalent in both refinements.
However, given
trait A { val a: Int }
trait B { val b: String }
I'm getting
scala> implicitly[A with B =:= B with A]
res0: =:=[A with B,B with A] = <function1>
i.e. they are considered equivalent, even though the order of components is different. Why?
For example, a type constructor does not directly specify a type of values. However, when a type constructor is applied to the correct type arguments, it yields a first-order type, which may be a value type. Non-value types are expressed indirectly in Scala.
== is a final method, and calls . equals , which is not final. This is radically different than Java, where == is an operator rather than a method and strictly compares reference equality for objects. Save this answer.
=> is syntactic sugar for creating instances of functions. Recall that every function in scala is an instance of a class. For example, the type Int => String , is equivalent to the type Function1[Int,String] i.e. a function that takes an argument of type Int and returns a String .
Type declaration is a Scala feature that enables us to declare our own types. In this short tutorial, we'll learn how to do type declaration in Scala using the type keyword. First, we'll learn to use it as a type alias. Then, we'll learn to declare an abstract type member and implement it.
I think the =:=
evidence only asserts that each is the upper bound of the other.
trait A; trait B
import scala.reflect.runtime.{universe => ru}
val ab = ru.typeOf[A with B]
val ba = ru.typeOf[B with A]
ab =:= ba // false!
ab <:< ba // true!
ba <:< ab // true!
The implicit from Predef you get basically if LUB(X, Y) == X == Y, because then the implicit resolution finds =:=.tpEquals
with the inferred upper bound.
This is most likely what you want, because it means that you can treat one type as the other, and that works because the members of A with B
are equal to the members of B with A
even if the trait linearisation in the implementations is different.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With