Search code examples
scalainheritanceinstantiationmultiple-inheritancetraits

Why is it possible to instantiate multiple traits in Scala, but not a single one?


Let's say we have two traits:

trait Trait1
trait Trait2

If I try something like val single = new Trait1 I get an error error: trait Trait1 is abstract; cannot be instantiated. However, val twoTraits = new Trait1 with Trait2 compiles. Why is it so?

P.S. I also observed that val single = new Trait1 {} compiles just fine. Could you provide a proper explanation?


Solution

  • Technically, you can't instantiate a single trait or multiple mixed traits directly, but the compiler uses some syntactic sugar that allows you to create anonymous classes that extend them. Let's say we have:

    trait A
    trait B
    

    When you call new A with B, what's really happening is that the compiler is creating an anonymous class that mixes in both A and B. You get:

    final class $anon extends A with B
    new $anon()
    

    When you call new A {}, the same thing happens. You get an anonymous class that extends A:

    final class $anon extends A
    new $anon()
    

    The only difference is syntactical. When creating an anonymous class from a single trait, you are required to at least use braces {} to distinguish it from a class. That is, it is easier to discern whether the template can be constructed, or must be wrapped in an anonymous class to be constructed. With multiple traits (or even a class with traits mixed in), the compiler understands it will always need to create an anonymous class first.

    To summarize:

    class C
    
    new A {}       // Anonymous class that extends A, then constructed
    new A with B   // Anonymous class that extends A with B, then constructed
    new C          // Constructed instance of class C
    new C with A   // Anonymous class that extends C with A, then constructed