Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why compound types with different order of components are equivalent in Scala?

Tags:

scala

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?

like image 697
exlevan Avatar asked Aug 18 '15 09:08

exlevan


People also ask

How does Scala determine types when they are not specified?

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.

What is the difference between .equals and == 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.

What is the meaning of => in Scala?

=> 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 .

What is .type in Scala?

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.


1 Answers

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.

like image 140
0__ Avatar answered Oct 26 '22 01:10

0__