How to generate a default method for a Scala trait?


#1

Any thoughts on how a Scala trait’s method can become a default method? I didn’t find very much documentation on this. My aim is for Java programs to avoid having to provide an implementation of a given trait.

To expand, given the following trait:

  trait Provider[T <: SecretStore] {
    def acquireSecretStore(config: Config)(implicit mat: Materializer, system: ActorSystem): T
  }

I’m assuming that there’s no default method given that there’s no implementation. Here’s the javap output to confirm:

public interface com.github.huntc.streambed.identity.SecretStore$Provider<T extends com.github.huntc.streambed.identity.SecretStore> {
  public abstract T acquireSecretStore(com.typesafe.config.Config, akka.stream.Materializer, akka.actor.ActorSystem);
}

If I then provide an implementation:

  trait Provider[T <: SecretStore] {
    def acquireSecretStore(config: Config)(implicit mat: Materializer, system: ActorSystem): T =
      doAcquireSecretStore(config)
    
    def doAcquireSecretStore(config: Config)(implicit mat: Materializer, system: ActorSystem): T
  }

My, perhaps unreasonable, expectation is that acquireSecretStore will become a default method. Unfortunately not as per the following javap output:

public interface com.github.huntc.streambed.identity.SecretStore$Provider<T extends com.github.huntc.streambed.identity.SecretStore> {
  public static com.github.huntc.streambed.identity.SecretStore acquireSecretStore$(com.github.huntc.streambed.identity.SecretStore$Provider, com.typesafe.config.Config, akka.stream.Materializer, akka.actor.ActorSystem);
  public T acquireSecretStore(com.typesafe.config.Config, akka.stream.Materializer, akka.actor.ActorSystem);
  public abstract T doAcquireSecretStore(com.typesafe.config.Config, akka.stream.Materializer, akka.actor.ActorSystem);
  public static void $init$(com.github.huntc.streambed.identity.SecretStore$Provider);
}

Thanks for any guidance.


#2

On further investigation, I see that javap outputs no flag in relation to default - this is a misunderstanding on my part. I can see that Scala 2.12 lays out the byte code for the default method as per Java 8.


#3

I was curious if it’s easy or possible to discover the release notes for 2.12, see “Traits compile to interfaces” for caveats on Java interop.


#4

Yes it was. The problem was really just down to my misunderstanding of javap in relation to the default qualifier.


#5

Side note: personally I almost never use javap, but asm instead.

$> cat $(which asm)
#!/bin/sh

files="$@"

asm_jar=~/Applications/bin/asm-5.0.2/lib/all/asm-all-5.0.2.jar
asm_main=org.objectweb.asm.util.Textifier

for f in $files; do
  dirname=$(dirname "$f")
  basename=$(basename "$f")
  class=${basename%%.class}
  java -cp $asm_jar $asm_main -debug $f > $dirname/$class.asm
done

And, in many cases, instead of using asm, the output of cfr-decompiler is enough to study a problem (and easier to read than asm).