Aux-pattern usage compiles without inferring an appropriate type

人盡茶涼 提交于 2021-02-04 19:20:27

问题


Consider the following simple example involving Aux-pattern:

sealed trait AdtBase

abstract case class Foo(){
  type T <: AdtBase
}

object Foo{
  type Aux[TT] = Foo { type T = TT }
}

abstract case class Bar(){
  type T <: AdtBase
  val foo: Foo.Aux[T]
}

object Bar {
  type Aux[TT] = Bar { type T = TT }

  def apply[TT <: AdtBase](f: Foo.Aux[TT]): Bar = new Bar() {
    override type T = TT
    override val foo: Foo.Aux[T] = f
  }
}

case class Baz(foo: Foo)

def testBaz(baz: Baz) = Bar(baz.foo) //Compiles fine
def testFoo(foo: Foo) = Bar(foo) //Error: Type mismatch

Scastie

I don't really understand why testBaz compiles. I expected type mismatch as well.


回答1:


It seems there is no deep reason for that.

Since when you specify type parameter explicitly both methods compile

def testBaz(baz: Baz) = Bar[baz.foo.T](baz.foo) //compiles
def testFoo(foo: Foo) = Bar[foo.T](foo)         //compiles

it seems in

def testBaz(baz: Baz) = Bar(baz.foo) //compiles
//def testFoo(foo: Foo) = Bar(foo)   //doesn't compile

in the first case the type baz.foo.T is inferred while in the second case the type foo.T is just not inferred

// found   : Foo
// required: Foo.Aux[this.T]

In Scala it's always possible that some type parameter will not be inferred and you'll have to specify it explicitly.


Maybe I found a possible reason.

The code

class testFoo2(foo: Foo) {
  // Bar(foo) // doesn't compile
}

doesn't compile but if you make foo a val

class testFoo2(val foo: Foo) {
  Bar(foo) // compiles
}

then it does. Probably the thing is that when foo is a val it's more "stable" and in such case it's "easier" to infer path-dependent type foo.T.

So the difference between testBaz and testFoo can be that Baz is a case class so foo is a val while in testFoo foo is just a method parameter and therefore less "stable".

Similarly , on contrary to

trait A[T]
def m[T](a: A[T]) = ???
m(??? : A[_]) // compiles

the code

trait A { type T } 
def m[_T](a: A { type T = _T}) = ??? 
m(??? : A) // doesn't compile

doesn't compile but if we extract a variable

val a: A = ???
m(a) // compiles

then it does. The thing is that now a is stable and type a.T can be inferred.



来源:https://stackoverflow.com/questions/64672950/aux-pattern-usage-compiles-without-inferring-an-appropriate-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!