Generate copy method for sealed traits that are only extended by case classes

1,019 views
Skip to first unread message

cdue...@gmail.com

unread,
Nov 29, 2013, 9:48:30 AM11/29/13
to scala-i...@googlegroups.com
Suppose I have the following:

    sealed trait T { val foo: Int }
    case class A(foo: Int) extends T
    case class B(foo: Int, bar: String) extends T

If I have a function like

    def f(t: T): T = {
        val foo = ...
        t.copy(foo = foo)
    }

I get an error: value copy is not a member of T. This is true; only A and B have a copy method. But since T is a sealed trait and the only classes extending T are case classes with synthetically generated copy methods, shouldn't the compiler be able to prove that all instances of T have a copy method?

I can get around this by doing the proof manually:

    def f(t: T): T = {
       val foo = ...
       t match {
           case a: A => a.copy(foo = foo)
           case b: B => b.copy(foo = foo)
       }
    }

but this is repetitive and I'd rather the compiler be able to do this for me. From a high level: if a sealed trait with abstract vals is extended only by case classes, then generate a copy method for the trait only for the abstract vals it defines. Someone with more experience with Scala's internals could probably flesh this out a bit more.

Are there any issues with something like this? If a feature like this is desirable, I'd like to contribute a patch.

Jason Zaugg

unread,
Nov 29, 2013, 10:07:10 AM11/29/13
to scala-i...@googlegroups.com
On Fri, Nov 29, 2013 at 3:48 PM, <cdue...@gmail.com> wrote:
Suppose I have the following:

    sealed trait T { val foo: Int }
    case class A(foo: Int) extends T
    case class B(foo: Int, bar: String) extends T

If I have a function like

    def f(t: T): T = {
        val foo = ...
        t.copy(foo = foo)
    }

I get an error: value copy is not a member of T. This is true; only A and B have a copy method. But since T is a sealed trait and the only classes extending T are case classes with synthetically generated copy methods, shouldn't the compiler be able to prove that all instances of T have a copy method?

Sealedness is only used to enumerate direct subclasses so as to issue warnings in pattern matches that can be shown to be non-exhaustive or have impossible cases. I don't think we would accept language changes that inferred interfaces based on subclass.

But you would actually have a few more basic problems to solve:

 - those copy methods don't have the same signature, the compiler is inserting the extra default parameters that you omit in the call to B#copy
 - synthetic case class methods like copy can't implement interfaces (https://issues.scala-lang.org/browse/SI-5122)

If you wanted to get adventurous, you could write a macro to do some of this magic. The guys at Habla Computing have been toying with this idea in https://github.com/hablapps/updatable

But I would probably advise you to live with the boilerplate in this case and avoid a trip down the rabbit hole :)

-jason

√iktor Ҡlang

unread,
Nov 29, 2013, 10:19:23 AM11/29/13
to scala-i...@googlegroups.com
Ye olde 5122, would love to see that one fixed ;)


--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Cheers,

Viktor Klang

Director of Engineering

Twitter: @viktorklang
Reply all
Reply to author
Forward
0 new messages