It works, you need to instantiate an abstract subclass. Constructor is hidden, no default apply, no copy. Pattern matching works.
sealed abstract case class Foo private (s: String, n: Int)
object Foo {
def apply(s: String): Foo =
new Foo(s, s.length) {}
}
Foo("x", 42) // nope
new Foo("x", 42) // nope
val a = Foo("x")
// a: Foo = Foo("x", 1)
a.copy(n = 42) // nope
val Foo(s, n) = a
// s: String = "x"
// n: Int = 1