0

I would like to define a class hierarchy with about 100 case classes deriving from common base. The types are describing nodes in the AST hierarchy, like this one. I would like to do something along the lines of:

trait Base { def doCopy: Base } trait CloneSelf[T <: CloneSelf[T]] extends Base { self: T => def copy(): T override def doCopy: T = copy() } case class CaseA(a: String) extends Base with CloneSelf[CaseA] case class CaseB(b: Int) extends Base with CloneSelf[CaseB] 

This gives an error, because the existence of my copy prevents the case classes from defining the automatic copy. Is there some way how to implement the "clone" doCopy so that is uses the automatic copy of those case classes?

2 Answers 2

1

I would like to define a class hierarchy with about 100 case classes deriving from common base.

Please do not do that, you should absolutely find a pattern to avoid it! If you want to do this anyway... Try ducktyping:

trait CloneSelf[T <: {def copy(): T}] { self: T => override def doCopy: T = copy() } 

I cannot test now so this probably won't compile, but you can figure it out by yourself with the general idea!

Edit:

Why having 100 subclasses is evil: imagine you perform one change in the base class, for instance change its name from Base to BaseCloning -> you'll have to change it in EVERY child class (100 changes).

How you will avoid that depends on what you want to do with your classes, check creationnal and structural patterns: factory, builder, prototype, flyweight, composite... Always think about "how much work will I have if I change something in the base class? Will it affect all children?"

Sign up to request clarification or add additional context in comments.

5 Comments

Are there some common patterns how to design the hierarchy to avoid this, while still getting the automatic copy? (And could you elaborate what evil is in doing this?)
"imagine you perform one change in the base clase". I fail to see his reason, as I am using IDE or search and replace for this, therefore it does matter how many classes. Is there any serious reason why this is evil? Normal changes in the base class do not force me to change anything in the derived classes, as they just inherit the changes.
"you'll have to change it in EVERY child class" . . . or let your IDE do it for you.
Yes because I used a naming example so your IDE can do this for you. But he cannot perform business logic changes. It is very hard to explain as you don't want to explain what you'll end up doing with those classes. What if you add a second parameter type to CloneSelf, let's say, the type of the subclasse parameter?
I have added an explanation about the purpose - the types describe an AST (coming out of a parser).
0

I have found out defining the doCopy in each case class is actually less work than defining each class to inherit from CloneSelf. The code looks like this:

trait Base { def doCopy: Base } case class CaseA(a: String) extends Base { def doCopy = copy() } case class CaseB(b: Int) extends Base { def doCopy = copy() } 

I was surprised to learn that without explicit type on the overridden method the type is inferred by the compiler, therefore the static type of CaseA("a").doCopy is the same as of CaseA("a").copy(), i.e. CaseA, not Base. Adding explicit type for each case class would be probably more obvious, but this would require more work compared to just copy-pasting the same line into each of them. Not that it matters much - when I do copying via the case class type, I may use the copy() as well. It is only when I have the Base I need the doCopy, therefore declaring it like def doCopy: Base = copy() would do little harm.

3 Comments

You may want to consider naming your method clone and extending scala.Cloneable (which extends java.lang.Cloneable).
Right. I wanted this example to be simple, and overriding clone has its own peculiarities which I wanted to avoid here - at least in Java, is this different in Scala?
I wouldn't say that it's different. I'm just thinking that if I were a new developer on your team then I'd wonder how different doCopy is from clone.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.