【问题标题】:Reified generics in Scala 2.10Scala 2.10 中的具体泛型
【发布时间】:2011-12-22 14:33:15
【问题描述】:

Scala 中缺乏具体化的泛型是该语言最困扰我的地方,因为如果不使用复杂的构造,simple things 就无法实现。

Kotlin 和 Ceylon 都支持物化泛型,因此绝对可以在 JVM 之上这样做。在past 中,据说Scala 无法在不更改JVM 的情况下支持它们,但现在Scala 2.10 是rumored,对具体化的支持有限。所以我的问题是:

  • 我们可以期待 Scala 2.10 中的具体化,例如,我是否能够实现 generic trait multiple times ?到底有多大限制?
  • 如果 Scala 2.10 的具体化结果比KotlinCeylon 更有限。这是为什么呢?

【问题讨论】:

  • 我尝试更新问题,以便现在希望更容易回答(如是/否,您不能在 Scala 2.10 中多次实现通用特征,因为类型具体化需要在生成的类中进行名称修改,让它们在 Java 中使用起来很复杂。或者不管答案是什么。
  • Odersky 物化是在 2.10,所以这不仅仅是谣言。
  • 您的意思是不存在的 Kotlin 和 Ceylon-that-was-just-release-without-reification 表明物化泛型是可能的?它是如何工作的?
  • 我无法理解这个问题怎么会被认为是“没有建设性的”。这个问题非常客观,并且有明确的答案,尽管提及的语言/功能尚不可用。

标签: generics scala ceylon kotlin


【解决方案1】:

你的论点有缺陷。 Kotlin 还没有发布*,Ceylon 刚刚发布了它的第一个版本,我将引用 their announcement 中缺少的一个东西:

  • 具体化的泛型

所以,对不起,但是 什么 实现证明这是可能的?事实上,我并没有过多关注 Kotlin 的前景,但 Ceylon 所承诺的正是 manifest 已经提供的东西,而且是以透明的方式提供的。

但是让我们考虑一下您在问题中描述的问题:

trait Handles[E <: Event] {
  def handle(event: E)
}

所以,首先,JVM 没有提供任何方法来识别接口或类中的类型参数,所以E 无法被 JVM 检查。但是,您可以在实现 Handles 的每个对象中存储有关 E 代表什么的信息,就像您可以在 Scala 中编写此代码一样:

abstract class Handles[E <: Event : Manifest] {
  def handle(event: E)
}

接下来,我们来看handle的方法。同样,JVM 没有提供在方法定义中使用类型参数的方法。实现它的唯一方法是让handle 接受Object 作为参数:即,键入擦除。

这就是交易:要使handle 可以从Java 中调用,它必须被类型擦除。而且,如果它被类型擦除,那么它会受到您问题中描述的限制。解决这个问题的唯一方法是放弃 Java 兼容性(顺便说一下,这在 Ceylon 的第一个版本中也不可用)。

是的,根据 Martin Odersky 的说法,Scala 将在 2.10 上进行(某种形式的)具体化。但无论它提供什么(我打赌更透明地使用清单来断言类型相等),这个特殊的限制是 JVM 固有的,如果不放弃 Java 集成就无法克服。

(*) Kotlin 现在有一个演示,它的具体化——到目前为止——只是捆绑清单和 instanceOf 测试的语法糖。它仍然受到 Scala 的所有相同限制。

【讨论】:

  • 我认为既然规范提到了具体化(fx.goo.gl/jMvzG),作者确实找到了一种方法来做到这一点。如果不是,那么你是完全正确的。我的问题更多是关于 2.10 中泛型的性质以及为什么 kotlin 和 ceylon 可以解决这个问题而 Scala 不能(假设他们可以)。
  • @Lars:不,如果不在 JVM、类文件、字节码和语言之间创建一个全新的抽象,就无法在 JVM 上进行适当的具体化泛型。尽管有两种新语言声称支持具体化的泛型,但这些语言迄今为止除了一些美化的 instanceOf 测试之外什么也没提供。
  • Gosu 支持物化泛型,尽管 Kotlin 和 Ceylon 没有发布支持它们的版本,但毫无疑问,它们也会支持它们。话虽如此,我认为在 Scala 中添加具体化的泛型是一个错误,会对该语言造成影响,而需要访问泛型信息的情况非常罕见,并且通常可以通过清单充分满足。戈苏链接:gosu-lang.org/doc/Gosu%20Reference%20Guide/wwhelp/wwhimpl/…
  • 虽然我知道这个星球上没有任何事实可以改变你的观点,但你真的检查过你的主张吗? :-) 只是一个示例“错误:具有相同名称的方法在字节码级别具体化为相同的签名。重命名其中一个方法。”。请注意“擦除”如何方便地被“具体化”取代?如果编译器在尝试实现简单接口时不会完全不稳定并崩溃(“java.lang.ClassFormatError: Illegal field modifiers in class program_/__Program__689”),我可以继续。
  • 顶部的一行更新说明,会和你刚刚留下的评论一样快。
【解决方案2】:

Kotlin 已经为内联函数类型参数重新定义了泛型,如下所述:https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters。这在 Kotlin 中已经存在了一段时间,它们已被 Kotlin 生态系统中的许多库使用。当提到 Kotlin 时,这里的其他答案已经过时了。 Kotlin 自 2016 年 2 月起以 1.0 的形式发布。

Kotlin 中的具体化泛型示例,Jackson 中著名的TypeReference,在Jackson Kotlin module 中使用时使用此代码:

public inline fun <reified T: Any> ObjectMapper.readValue(jp: JsonParser): T 
     = readValue(jp, object: TypeReference<T>() {})

来自基于 Kotlin 的 Injekt 库的相同内容:

public inline fun <reified T: Any> fullType(): FullTypeReference<T> 
    = object:FullTypeReference<T>(){}

public inline fun <reified T : Any> injectLazy(): Lazy<T> {
    return lazy { Injekt.get(fullType<T>()) }
}

【讨论】:

    【解决方案3】:

    根据 Andrey Breslav 在 this 页面上所说的话,Kotlin 没有具体类型:

    “是的,类对象中没有类型参数”

    【讨论】:

    • Kotlin 中删除了 Reified 类型:“Reified generics 只能在 JVM 上实现,性能开销很大,我们决定取消此功能。”。见devnet.jetbrains.com/message/5479326#5479326
    • 同时,Ceylon 的下一个里程碑版本将包含 reified generics ceylon-lang.org/blog/2013/02/21/reification-finally
    • @Ollip 您的答案应该更新,Kotlin 确实为内联函数重新定义了泛型,这些泛型被大量使用并解决了最常见的情况。您的回答现在对当前的 Kotlin 具有误导性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 2020-03-27
    • 2019-02-02
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多