8

由于auxWindows 下的包名称存在问题,我正在从库的包层次结构中移动一个帮助类

de.sciss.scalainterpreter.aux

de.sciss.scalainterpreter

该类是库私有的,即private[scalainterpreter] object Helper.

现在使用Typesafe Migration-Manager,显然它报告更改不兼容:

Found 2 binary incompatibiities
===============================
 * class de.sciss.scalainterpreter.aux.Helper does not have a correspondent
   in new version
 * object de.sciss.scalainterpreter.aux.Helper does not have a correspondent
   in new version

但我怀疑如果客户端代码没有调用任何一个对象,接口仍然兼容,因此我可以使用小版本增加来表示更改,并允许这两个版本互换使用。

正确的?

4

3 回答 3

3

您没有指定Helper在移动之前是否已经包私有。所以我会处理这两种情况:

  • 如果它已经是私有包:

    我怀疑迁移管理器报告不兼容只是因为它必须保持保守:包是在 scala 中打开的(就像在 java 中一样),这意味着客户端代码很可能会定义一个类 package scalainterpreter。因此,通过移动Helper,您确实会打破该课程。

    但是,让我们务实一点:de.sciss.scalainterpreter.aux您的包(它们的子包也应该是),没有人应该在那里定义自己的类。有了这个额外的先决条件,移动Helper确实是对客户端scala代码的二进制兼容更改。

    至于客户端java代码,它有点不同,因为即使Helper是包私有的,它的可见性仍然public对JVM而言,因此java编译器会很乐意让客户端代码访问Helper(因此客户端java代码很可能已经访问Helper,尽管它被声明为包私有)。

  • 如果在移动之前它不是私有包:

    好吧,运气不好。客户端代码很可能已经访问Helper了,而此举肯定会破坏这一点。作为旁注,您可以使用一个小技巧来使更改源兼容,但可惜不是二进制兼容的。只需添加以下文件:

    package de.sciss
    
    package object scalainterpreter {
      object aux {
        val Helper = _root_.de.sciss.scalainterpreter.Helper
      }
    }
    

有了上面,你仍然可以访问Helperas de.sciss.scalainterpreter.aux.Helper,并且它仍然在 windows 下编译(不像定义一个 package aux,它因为作为文件名的保留含义而无法编译)。但同样,这不是二进制兼容的,只有源兼容。

于 2012-09-06T15:30:40.423 回答
1

很容易看出内联如何破坏客户端代码,因为内联代码本质上会渗入客户端界面。这个例子确实要求链接错误;我们可以试验并做类似 javap | 的事情。grep Helper,但在某种程度上你必须让 scalac 完成它的工作。

package lib {

  object Lib {
    //import util.Helper
    @inline def result = Helper.help
  }

  //package util {

  private [lib] object Helper {
    @inline def help = "Does this help?"
  }
//}
}

样品无辜旁观的客户:

package client

object Test {
  import lib.Lib
  def main(args: Array[String]) {
    println(Lib.result)
  }
}

更改包私有类的包:

$ scala -cp "classes;target" client.Test
Does this help?

apm@halyard ~/tmp/taking-it-private
$ vi lib.scala

apm@halyard ~/tmp/taking-it-private
$ rm -rf classes/*

apm@halyard ~/tmp/taking-it-private
$ smalac -d classes -optimise lib.scala 

apm@halyard ~/tmp/taking-it-private
$ smala -cp "classes;target" client.Test
java.lang.ClassNotFoundException: lib.util.Helper$

Javap 说明了原因。[即,调用是内联的,但它仍想初始化模块。]

我没有关注这些讨论,但例如有链接: https ://github.com/scala/scala/pull/1133 和其他关于 ML 的讨论,关于对二进制兼容性的期望是有效的。 https://groups.google.com/forum/?fromgroups=#!topic/scala-internals/sJ-xnWL_8PE

于 2012-09-06T16:52:33.317 回答
0

简而言之,没有理由不这样做。链接发生在签名周围;由于所讨论的对象仅限于编译单元,客户端不能(或者更确切地说,不应该)使用它,因此二进制兼容性不是问题。

于 2012-09-06T15:06:09.357 回答