Перемещение закрытого пакета - должен ли я считать этот двоичный файл несовместимым?
Из-за проблемы с именем пакета aux
под Windows я перемещаю вспомогательный класс в иерархию пакетов моей библиотеки из
de.sciss.scalainterpreter.aux
в
de.sciss.scalainterpreter
Класс является частным для библиотеки, т.е. private[scalainterpreter] object Helper
,
Теперь используя http://typesafe.com/technology/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
Но я подозреваю, что если клиентский код не обращается ни к одному из объектов, интерфейсы по-прежнему совместимы, и, таким образом, я могу использовать незначительное увеличение версии, чтобы указать на изменение, и разрешить использование этих двух версий взаимозаменяемо.
Правильный?
3 ответа
Легко увидеть, как встраивание может нарушить клиентский код, поскольку встроенный код по существу сливается с клиентским интерфейсом. Этот пример действительно запрашивает ошибку связи; мы можем экспериментировать и делать такие вещи, как javap | grep Helper, но на каком-то уровне вы должны позволить скалаку делать свою работу.
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=
Вы не указываете, если Helper
до переезда была уже частная посылка. Поэтому я рассмотрю оба случая:
Если это был уже пакет private:
Я подозреваю, что менеджер миграции сообщает о несовместимости только потому, что она должна оставаться консервативной: пакеты открываются в Scala (как в Java), что означает, что клиентский код может очень хорошо определить пакет класса
scalainterpreter
, Итак, двигаяHelper
Вы действительно сломаете этот класс.Однако давайте будем прагматичны:
de.sciss.scalainterpreter.aux
это ваш пакет (и так же должны быть их подпакеты), и никто не должен определять свои собственные классы там. С этой дополнительной предпосылкой, двигаясьHelper
действительно бинарно-совместимое изменение к клиентскому скала- коду.Что касается клиентского Java- кода, он немного отличается, потому что даже если
Helper
пакет закрыт, его видимость все ещеpublic
что касается JVM, и, таким образом, компилятор java с радостью разрешит клиентскому коду доступHelper
(таким образом, клиентский Java-код вполне может получить доступHelper
, несмотря на то, что он объявлен частным пакетом).Если он не был закрытым до переезда:
Ну, удачи. Клиентский код вполне может получить доступ
Helper
и этот шаг наверняка сломает это. Как примечание, вы можете использовать небольшую хитрость, чтобы сделать изменение совместимым с источником, но, увы, не совместимым с двоичным кодом. Просто добавьте следующий файл:package de.sciss package object scalainterpreter { object aux { val Helper = _root_.de.sciss.scalainterpreter.Helper } }
С вышеизложенным, вы все еще можете получить доступ Helper
как de.sciss.scalainterpreter.aux.Helper
и он все еще компилируется под windows (в отличие от определения пакета aux
, который не компилируется из-за зарезервированного значения как имени файла). Но опять же, это не двоичная совместимость, только совместимость с источником.
Проще говоря, нет причин, почему это не будет. Связь происходит вокруг подписей; поскольку рассматриваемый объект находится в области компиляции, клиенты не могут (или, скорее, не должны) использовать его, и поэтому двоичная совместимость не является проблемой.