Path-dependent types without a path?

Consider this trivial example:

class Outer {
  case class Inner()
  def test(i: Inner) = {}
}

As expected, this does not compile due to type mismatch:

val o1 = new Outer()
val o2 = new Outer()

o1.test(o2.Inner())  // doesn't compile

What if we want to define an autonomous function?

This is not good

def test[X <: Outer](a: X#Inner, b: X#Inner) = {}

because it compiles as if everything is fine

test(o1.Inner(), o2.Inner())

It works

def test(x: Outer)(a: x.Inner, b: x.Inner) = {}

because it compiles:

test(o1)(o1.Inner(), o1.Inner())

and this is not so:

test(o1)(o1.Inner(), o2.Inner())

However, we need to pass an additional argument Outerto test. Can this be avoided? Ideally, the following should work:

test(o1.Inner(), o1.Inner()) // ok
test(o1.Inner(), o2.Inner()) // compilation error
+4
source share
2 answers

I do not think that it can be ensured from the box. For example, one of the possible solutions could be:

scala> def test[X <: Outer#Inner](a: X)(b: X) = ()
test: [X <: Outer#Inner](a: X)(b: X)Unit

scala> test(o1.Inner())(o1.Inner())

scala> test(o1.Inner())(o2.Inner())
<console>:16: error: type mismatch;
 found   : o2.Inner
 required: o1.Inner
       test(o1.Inner())(o2.Inner())
                                ^

, , . ( @OlivierBlanvillain, )

scala> test[Outer#Inner](o1.Inner())(o2.Inner())

:

scala> def test[X <: Outer](a: X#Inner)(b: X#Inner) = ()
test: [X <: Outer](a: X#Inner)(b: X#Inner)Unit

scala> test(o1.Inner())(o2.Inner())

, scalac infers X Outer, , Outer . X , o1 o2, - , . . Scala Singleton. :

scala> def test[X <: Outer with Singleton](a: X#Inner)(b: X#Inner) = ()
test: [X <: Outer with Singleton](a: X#Inner)(b: X#Inner)Unit

scala> test(o1.Inner())(o1.Inner())
<console>:15: error: inferred type arguments [Outer] do not conform to method test type parameter bounds [X <: Outer with Singleton]
       test(o1.Inner())(o1.Inner())
       ^
<console>:15: error: type mismatch;
 found   : o1.Inner
 required: X#Inner
       test(o1.Inner())(o1.Inner())
                    ^

! , scalac . :

scala> test[o1.type](o1.Inner())(o1.Inner())

:

scala> test(o1.Inner())(o2.Inner())
<console>:16: error: inferred type arguments [Outer] do not conform to method test type parameter bounds [X <: Outer with Singleton]
       test(o1.Inner())(o2.Inner())
       ^
<console>:16: error: type mismatch;
 found   : o1.Inner
 required: X#Inner
       test(o1.Inner())(o2.Inner())
                    ^

scala> test[o1.type](o1.Inner())(o2.Inner())
<console>:16: error: type mismatch;
 found   : o2.Inner
 required: o1.Inner
       test[o1.type](o1.Inner())(o2.Inner())
                                         ^

scala> test[Outer](o1.Inner())(o2.Inner())
<console>:17: error: type arguments [Outer] do not conform to method test type parameter bounds [X <: Outer with Singleton]
       test[Outer](o1.Inner())(o2.Inner())
           ^

, , , ...


, - , , , : -p

META EDIT, , , , , , .

scala> import scala.language.existentials
import scala.language.existentials

scala> def test[X <: x.Inner forSome { val x: Outer }](a: X, b: X) = ()
test: [X <: x.Inner forSome { val x: Outer }](a: X, b: X)Unit

scala> test(o1.Inner(), o1.Inner())

scala> test(o1.Inner(), o2.Inner())
<console>:16: error: inferred type arguments [Outer#Inner] do not conform to method test type parameter bounds [X <: x.Inner forSome { val x: Outer }]
       test(o1.Inner(), o2.Inner())
       ^
<console>:16: error: type mismatch;
 found   : o1.Inner
 required: X
       test(o1.Inner(), o2.Inner())
                    ^
<console>:16: error: type mismatch;
 found   : o2.Inner
 required: X
       test(o1.Inner(), o2.Inner())
                                ^

scala> test[o1.Inner](o1.Inner(), o2.Inner())
<console>:16: error: type mismatch;
 found   : o2.Inner
 required: o1.Inner
       test[o1.Inner](o1.Inner(), o2.Inner())
                                          ^
+4

:

scala> def t[X <: Outer#Inner, Y <: Outer#Inner](a: X, b: Y)(implicit e: X =:= Y)=1
test: [X <: Outer#Inner, Y <: Outer#Inner](a: X, b: Y)(implicit ev: X =:= Y)Unit

scala> test(o1.Inner(), o1.Inner()) // ok

scala> test(o1.Inner(), o2.Inner())
<console>:15: error: Cannot prove that o1.Inner =:= o2.Inner.
       test(o1.Inner(), o2.Inner())
           ^

, .

+4

Source: https://habr.com/ru/post/1679447/


All Articles