Bad Java, no cake for you! – Java 8 default methods versus Scala traits

Java 8 was released recently and one of the much heralded features is Default methods. Simply put, these allow you to inject functionality to classes via interfaces. This is a new feature in that prior to Java 8, Interfaces could only have method signatures and not have the implementation and only Abstract classes could have method implementations but that has now changed.

Here’s a simple example that prints out “In InterfaceOne”

In Scala, another JVM language, you can do something similar but more awesome with Scala’s traits (its version of interfaces) you can override similar implementations and have a version of multiple inheritance. This example prints out “In TraitTwo”

The secret that avoid that diamond of death is that whichever trait is declared last wins. If I’d swapped around the order that the traits were declared then it would have printed “In TraitOne”

What is even nicer in Scala is that you can declare your class with traits when you instantiate it. You don’t have to declare it at the compile time of the class. This means that you have a powerful way to extend functionality of classes but without the insanity of monkey patching. ThisThe below example also prints out “In TraitTwo” but the class does not extend any trait. This of course is Scala’s cake pattern where you can mix in the traits.

What is slightly disappointing with Java 8 is that you cannot mimic this behaviour. If you try to do this in Java 8, you get a nice compile time error telling us the class inherits unrelated defaults.

I wonder why they chose not to support this. The cake patterns seems like a feature that adds flexibility without being able to shoot yourself in the foot too much.

 

2 thoughts on “Bad Java, no cake for you! – Java 8 default methods versus Scala traits

  1. Gokan EKINCI

    I would not say “awesome” for Scala’s Trait , because as you said your Scala example prints “InTraitTwo” because it takes the last “with Trait”‘s method. Now consider you have multiple Traits and you only want to take some methods from the first Trait and some methods from the second Trait, but your Traits have the same signature. You Java code will compile if you choose which method you want to call :

    // Will compile 😉
    class MyOtherJavaExample implements SubInterfaceOne, SubInterfaceTwo {
    @Override
    public void writeOut(){
    SubInterfaceOne.super.writeOut();
    }
    }

    No cake for Scala.

    Reply
    1. Nils

      Well, you can do the exact same thing in Scala, IF you need to override the default linearization behavior:

      val myExample = new MyExample with TraitOne with TraitTwo {
      override def writeOut() = super[TraitOne].writeOut()
      }

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>