Anonymous Inner Class Equivalent


#1

Hi,

I know that anonymous inner classes are, for the most part, replaced by lambda’s / inline functions in Kotlin. There are cases where being able to define a class inline / anonymous inner class is quite useful:

  • When there are several methods on the interface (and the implementation is small enough that it's easy to read inline)
  • When using Java code that has methods that take single method interfaces

e.g. If I have the following Java code:

interface Callback<T> {
void on(T object);
}

class Processor<T> {
  private final T t;
  public Processor(T t) { this.t = t; }
ute(Callback<T> callback) {
  // do some stuff and then call the callback
  }
}

If I wanted to call that code from Kotlin, is the best way to do something like:

fun main(args : Array<String>) {

  class TestCallback : Callback<String> {
  public override fun on(value: String?) {
           println(value)
  }
  }

  val t = Processor<String>(“Hello”)
  val callback = TestCallback()
  t.execute(callback)
}

regards, Jamie.

#2

Rats. That Processor class definition should be:

public class Processor<T> {   private final T t;   public Processor(T t) { this.t = t; }   public void execute(Callback<T> callback) {   // do some stuff and then call the callback   callback.on(t);   } }


#3

Use Kotlin object expressions http://confluence.jetbrains.net/display/Kotlin/Object+expressions+and+Declarations


#4

Thanks! I should have spotted that. I did discover that this code would cause a compiler error, should I raise a ticket?:

package org.example

/**

  • Compiler error
    */
    trait SomeTrait {

}

trait KotlinProcessor<T> {
  fun execute(callback: KotlinCallback<T>?);
}

trait KotlinCallback<T> {
  fun on(t : T);
}

public class Test(name : String) : KotlinProcessor<SomeTrait> {
  public override fun execute(callback: KotlinCallback<SomeTrait>?) {
  if(callback != null) {
           class InlineTrait : SomeTrait {

           }
           var inlineTrait = InlineTrait()
           callback.on(inlineTrait)
  }
  }
}

[Internal Error] org.jetbrains.jet.codegen.CompilationException: Back-end (JVM) Internal error: wrong code generatedjava.lang.ArrayIndexOutOfBoundsException null
Cause: java.lang.ArrayIndexOutOfBoundsException
File being compiled and position: (19,5) in …/src/org/example/VerifyErrorTest.kt
The root cause was thrown at: unknown
at org.jetbrains.jet.codegen.FunctionCodegen.endVisit(FunctionCodegen.java:467)
at org.jetbrains.jet.codegen.FunctionCodegen.generateMethodHeaderAndBody(FunctionCodegen.java:165)
at org.jetbrains.jet.codegen.FunctionCodegen.generateMethod(FunctionCodegen.java:105)
at org.jetbrains.jet.codegen.FunctionCodegen.gen(FunctionCodegen.java:85)
at org.jetbrains.jet.codegen.MemberCodegen.genFunctionOrProperty(MemberCodegen.java:49)
at org.jetbrains.jet.codegen.ClassBodyCodegen.generateDeclaration(ClassBodyCodegen.java:90)
at org.jetbrains.jet.codegen.ImplementationBodyCodegen.generateDeclaration(ImplementationBodyCodegen.java:1476)
at org.jetbrains.jet.codegen.ClassBodyCodegen.generateClassBody(ClassBodyCodegen.java:82)
at org.jetbrains.jet.codegen.ClassBodyCodegen.generate(ClassBodyCodegen.java:63)
at org.jetbrains.jet.codegen.MemberCodegen.genImplementation(MemberCodegen.java:86)
at org.jetbrains.jet.codegen.MemberCodegen.genClassOrObject(MemberCodegen.java:140)
at org.jetbrains.jet.codegen.NamespaceCodegen.generate(NamespaceCodegen.java:132)
at org.jetbrains.jet.codegen.NamespaceCodegen.generate(NamespaceCodegen.java:95)
at org.jetbrains.jet.codegen.state.GenerationStrategy.generateNamespace(GenerationStrategy.java:53)
at org.jetbrains.jet.codegen.state.GenerationStrategy.compileCorrectFiles(GenerationStrategy.java:77)
at org.jetbrains.jet.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.generate(KotlinToJVMBytecodeCompiler.java:359)
at org.jetbrains.jet.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyzeAndGenerate(KotlinToJVMBytecodeCompiler.java:302)
at org.jetbrains.jet.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyzeAndGenerate(KotlinToJVMBytecodeCompiler.java:275)
at org.jetbrains.jet.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModule(KotlinToJVMBytecodeCompiler.java:113)
at org.jetbrains.jet.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.java:134)
at org.jetbrains.jet.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.java:132)
at org.jetbrains.jet.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.java:54)
at org.jetbrains.jet.cli.common.CLICompiler.exec(CLICompiler.java:117)
at org.jetbrains.jet.cli.jvm.K2JVMCompiler.exec(K2JVMCompiler.java:181)
at org.jetbrains.jet.cli.jvm.K2JVMCompiler.exec(K2JVMCompiler.java:54)
at org.jetbrains.jet.cli.common.CLICompiler.exec(CLICompiler.java:47)
at sun.reflect.GeneratedMethodAccessor743.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jetbrains.jet.compiler.runner.CompilerRunnerUtil.invokeExecMethod(CompilerRunnerUtil.java:97)
at org.jetbrains.jet.compiler.runner.KotlinCompilerRunner.execInProcess(KotlinCompilerRunner.java:77)
at org.jetbrains.jet.compiler.runner.KotlinCompilerRunner.access$000(KotlinCompilerRunner.java:39)
at org.jetbrains.jet.compiler.runner.KotlinCompilerRunner$1.fun(KotlinCompilerRunner.java:62)
at org.jetbrains.jet.compiler.runner.KotlinCompilerRunner$1.fun(KotlinCompilerRunner.java:59)
at org.jetbrains.jet.compiler.runner.CompilerRunnerUtil.outputCompilerMessagesAndHandleExitCode(CompilerRunnerUtil.java:106)
at org.jetbrains.jet.compiler.runner.KotlinCompilerRunner.runInProcess(KotlinCompilerRunner.java:59)
at org.jetbrains.jet.compiler.runner.KotlinCompilerRunner.runCompiler(KotlinCompilerRunner.java:51)
at org.jetbrains.jet.plugin.compiler.JetCompiler.runCompiler(JetCompiler.java:141)
at org.jetbrains.jet.plugin.compiler.JetCompiler.doCompile(JetCompiler.java:130)
at org.jetbrains.jet.plugin.compiler.JetCompiler.compile(JetCompiler.java:94)
at com.intellij.compiler.impl.CompileDriver.a(CompileDriver.java:2017)
at com.intellij.compiler.impl.CompileDriver.a(CompileDriver.java:1340)
at com.intellij.compiler.impl.CompileDriver.a(CompileDriver.java:1046)
at com.intellij.compiler.impl.CompileDriver.a(CompileDriver.java:788)
at com.intellij.compiler.impl.CompileDriver.access$1200(CompileDriver.java:109)
at com.intellij.compiler.impl.CompileDriver$9.run(CompileDriver.java:736)
at com.intellij.compiler.progress.CompilerTask.run(CompilerTask.java:153)
at com.intellij.openapi.progress.impl.ProgressManagerImpl$TaskRunnable.run(ProgressManagerImpl.java:501)
at com.intellij.openapi.progress.impl.ProgressManagerImpl$2.run(ProgressManagerImpl.java:191)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:232)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.runProcess(ProgressManagerImpl.java:181)
at com.intellij.openapi.progress.impl.ProgressManagerImpl$8.run(ProgressManagerImpl.java:406)
at com.intellij.openapi.application.impl.ApplicationImpl$6.run(ApplicationImpl.java:465)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
at com.intellij.openapi.application.impl.ApplicationImpl$1$1.run(ApplicationImpl.java:153)
Caused by: java.lang.ArrayIndexOutOfBoundsException


#5

Yes, please report it to our tracker. Thanks!


#6

http://youtrack.jetbrains.com/issue/KT-3210