Oh yes.
Varargs versus Seq
def foo(xs: Int*): Int = xs.sum
↔
def foo(xs: Seq[Int]): Int = xs.sum
Source incompatible, but binary compatible. (both ways)
Change public to protected[Scope]
object Enclosing {
def foo(x: Int): Int = x
}
→
object Enclosing {
protected[Enclosing] def foo(x: Int): Int = x
}
Add a public method
final class Foo {
}
→
final class Foo {
def bar(): String = "bar"
}
is source incompatible for a user that has
implicit class FooExt(private self: Foo) extends AnyVal {
def bar(): String = "my bar"
}
def main(): Unit = {
val foo: Foo = ???
println(foo.bar())
}
Upgrading Foo without recompiling main preserves the old behavior of printing "my bar" (so binary compatible), but if main is recompiled, it now prints "bar" (source incompatible).
I could probably come up with other things, but those are the ones that immediately pop to my mind. The last one is particularly important to understand: it means that evolving a Scala library in a 100% source compatible way is virtually impossible. Maintaining binary compatibility is easier!