Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Companion module should be deprecated if class is deprecated #12706

Closed
som-snytt opened this issue Jun 3, 2021 · 3 comments
Closed

Companion module should be deprecated if class is deprecated #12706

som-snytt opened this issue Jun 3, 2021 · 3 comments

Comments

@som-snytt
Copy link
Contributor

Compiler version

3.0.0

Minimized code

@deprecated("will be removed", "0.1")
abstract class J
object J {
  def f(i: Int): String = i + "th"
}

Output

➜  snips scalac -deprecation -d /tmp -source 3.0-migration kdep.scala
-- Deprecation Warning: kdep.scala:4:28 ------------------------------------------------------------------------------
4 |  def f(i: Int): String = i + "th"
  |                          ^^^
  |method + in class Int is deprecated since 2.13.0: Adding a number and a String is deprecated. Use the string interpolation `s"$num$str"`
1 warning found

Expectation

In Scala 2, companion is deprecated if class is. No warning is emitted.

That was for scala/bug#2799 which is currently #11022.

Extending a deprecated class is not an exemption:

@deprecated("will be removed", "0.1")
abstract class C {
  def f(i: Int): String
}
// warn 2x
class D extends C {
  override def f(i: Int): String = i + "th"
}

@deprecated("will be removed", "0.1")
abstract class K {
  def f(i: Int): String
}
// nowarn in Scala 2 by companion rule, e.g., `scala.io.Position`
object K extends K {
  override def f(i: Int): String = i + "th"
}

Arguably, extending a deprecated class should also suppress deprecations. If I'm not supposed to extend, then it should be marked @deprecatedInheritance. (It's not outlandish that a base class is deprecated, for removal, but the subclass is not.)

@sjrd
Copy link
Member

sjrd commented Jun 4, 2021

In Scala 2, companion is deprecated if class is. No warning is emitted.

I think Scala 2 is at fault here. If the class is deprecated, the companion is not deprecated. It's only the warnings that get erroneously silenced. Actually that allows to create holes in the deprecation chain:

>scala -deprecation
Welcome to Scala 2.13.4 (OpenJDK 64-Bit Server VM, Java 1.8.0_222).
Type in expressions for evaluation. Or try :help.

scala> @deprecated("class is deprecated", "1.0.0") class Foo; object Foo { def bar: Int = 42 }
class Foo
object Foo

scala> new Foo()
           ^
       warning: class Foo is deprecated (since 1.0.0): class is deprecated
val res0: Foo = Foo@70c491b8

scala> Foo.bar
val res1: Int = 42

scala> @deprecated("class is deprecated", "1.0.0") class Foobar; object Foobar { def bar: Int = { new Foo(); 42 } }
class Foobar
object Foobar

scala> Foobar.bar
val res2: Int = 42

Observe that:

  • new Foo() triggers a deprecation warning
  • Foo.bar doesn't (so no, the companion itself is not deprecated)
  • The new Foo() inside Foobar.bar does not emit a warning, although it should
  • Through Foobar.bar, which does not emit a deprecation warning, I can call new Foo(), which was initially deprecated

So Scala 3 does the right thing here. Scala 2 is to blame.

@odersky
Copy link
Contributor

odersky commented Jun 4, 2021

Should we close this then?

@som-snytt
Copy link
Contributor Author

I agree the behavior is dubious.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants