[英]Path dependent types (on types and on inner classes)
While experimenting with path dependent types, I experienced some unexpected results:在试验路径依赖类型时,我遇到了一些意想不到的结果:
object Funny1 {
class X {
type Y = String
val y: Y = "y"
}
val x1 = new X
val x2 = new X
def foo(x: X)(y: x.Y): Unit = ()
def foo_diff(y1: x1.Y)(y2: x2.Y): Unit = () // 1.3
def foo_gen(y1: X#Y)(y2: X#Y) : Unit = ()
foo(x1)(x1.y)
foo(x1)(x2.y) // <-- 1.1 would expect this to fail
foo_diff(x1.y)(x2.y)
foo_diff(x2.y)(x2.y) // <-- 1.2 would expect this to fail
foo_gen(x1.y)(x2.y)
foo_gen(x2.y)(x2.y)
}
object Funny2 {
class X {
class Y {
}
}
val x1 = new X
val x2 = new X
val x1y = new x1.Y
val x2y = new x2.Y
def foo(x: X)(y: x.Y): Unit = ()
def foo_diff(y1: x1.Y)(y2: x2.Y): Unit = ()
def foo_gen(y1: X#Y)(y2: X#Y) : Unit = ()
foo(x1)(x1y)
// foo(x1)(x2y) // does not compile
foo_diff(x1y)(x2y)
// foo_diff(x2y)(x2y) // does not compile
foo_gen(x1y)(x2y)
foo_gen(x2y)(x2y)
}
object Funny3 {
trait X {
type Y
def y: Y
}
val x1 = new X {
override type Y = String
override def y: String = "y"
}
val x2 = new X {
override type Y = Int
override def y: Int = 3
}
def foo(x: X)(y: x.Y): Unit = ()
def foo_diff(y1: x1.Y)(y2: x2.Y): Unit = ()
def foo_gen(y1: X#Y)(y2: X#Y) : Unit = ()
foo(x1)(x1.y)
// foo(x1)(x2.y) // 3.1 fails as expected
foo_diff(x1.y)(x2.y)
// foo_diff(x2.y)(x2.y) // 3.2 fails as expected
foo_gen(x1.y)(x2.y)
foo_gen(x2.y)(x2.y)
}
object Funny3b {
trait X {
type Y
def y: Y
}
val x1 = new X {
override type Y = String
override def y: String = "y"
}
val x2 = new X {
override type Y = String
override def y: String = "y2"
}
def foo(x: X)(y: x.Y): Unit = ()
def foo_diff(y1: x1.Y)(y2: x2.Y): Unit = ()
def foo_gen(y1: X#Y)(y2: X#Y) : Unit = ()
foo(x1)(x1.y)
foo(x1)(x2.y) // 3b.1 does not fail
foo_diff(x1.y)(x2.y)
foo_diff(x2.y)(x2.y) // 3b.2 does not fail
foo_gen(x1.y)(x2.y)
foo_gen(x2.y)(x2.y)
}
Especially, I am interested in the answers to the questions:特别是,我对以下问题的答案很感兴趣:
x
as first parameter required in 1.3 foo_diff
?为什么在 1.3 foo_diff
不需要将x
作为第一个参数的foo_diff
?Thanks, Martin谢谢,马丁
I think the fundamental misunderstanding that underlies all of your question is that you assume that a construction:我认为构成你所有问题的根本误解是你假设一个结构:
trait / class ClassName {
type T = something
}
creates a dependent type.创建一个依赖类型。 It doesn't.它没有。 If you open the subsection 3.5.1 Equivalence of the section 3.5 "Relations between types" of the spec, you may see that:如果您打开规范的第 3.5 节“类型之间的关系”的第3.5.1节等效性,您可能会看到:
- If
t
is defined by a type alias typet = T
, thent
is equivalent toT
.如果t
由类型别名 typet = T
,则t
等价于T
。
That's why in your first example for example, compiler sees x1.Y
and x2.Y
and X#Y
as just String
.这就是为什么在您的第一个示例中,编译器将x1.Y
和x2.Y
和X#Y
视为String
。 If you substitute all that with just String
there are no questions left on why that code compiles.如果你只用String
代替所有这些,那么关于为什么该代码编译就没有问题了。
Similarly your 3rd example just define some aliases.同样,您的第三个示例只是定义了一些别名。 If you substitute those aliases with their definitions, it again becomes quite clear why that code compiles and fails.如果你用它们的定义替换这些别名,那么代码编译和失败的原因就变得很清楚了。
Your second example uses a different construct您的第二个示例使用不同的构造
trait / class ClassName {
trait / class InnerName
}
This is the construct that creates a path-dependent type and thus the code you expect to not compile actually fails.这是创建依赖于路径的类型的构造,因此您期望不编译的代码实际上失败了。 According to my understanding this is the only of your examples that really involves dependent types.根据我的理解,这是您唯一真正涉及依赖类型的示例。
Also if you open Tour of Scala articles Abstract Type Members and Inner Classes that describe the first and the second construction, you might notice that only the latter (but not the former!) mentions the "path-dependent types".此外,如果您打开描述第一个和第二个构造的 Scala 文章抽象类型成员和内部类,您可能会注意到只有后者(而不是前者!)提到了“路径依赖类型”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.