What to do to make this compile?

Hello,

I have some Kotlin beginner question. I wrote my own little select method that does basically the same as the Collection.filter method. Problem is that I don’t understand the compilation error in the code below. I don’t really see why the Collection.filter counterpart compiles fine whereas my select test case doesn’t (see comment compiler errors). Played around for a while but then gave up. Seems there is something I’m missing and won’t find out about that quickly. Any suggestions?

Thanx, Oliver

fun main(args : Array<String>)
{
  val list = ArrayList<Int>()
  list.add(1)
  list.add(2)
  list.add(3)

  var filteredList = list.filter({ item -> item >= 2})   // compiles fine
  var otherFilteredList : List<Int> = list.filter({ item -> item >= 2})   // compiles fine
  var folteredCollection : Collection<Int> = list.filter({ item -> item >= 2})   // compiles anyway

  var selectList = list.select({item -> item >= 2})  // compiles fine
  var selectCollection : Collection<Int> = list.select({ item -> item >= 2})  // compiles fine
  var otherSelectList : List<Int> = list.select({ item -> item >= 2})   // compiler errors
}

fun <T> Collection<T>.select(condition : (T) -> Boolean) : Collection<T>
{
  var result = newInstanceNotNull()
  for (item in this) {
  if (condition(item))
           result.add(item)
  }
  return result
}

fun <T> Collection<T>.newInstanceNotNull() : Collection<T>
{
  val result = javaClass.newInstance()
  if(result != null)
  return result
  return ArrayList<T>
}

BTW there's no need for the parens around the { } blocks.

list.filter { it > 10 }

What compile error do you get?

As an aside, in general if ever the type inferencer can't figure something out, either add a type to the method parameter...

list.select{ (item: Int) -> item > 5 }

or add a type hint to the method call

list.select<Int>{ it > 5 }

BTW there's no need for the parens around the { } blocks.

This is cool. I didn't know...

What compile error do you get?

The compiler errors are:

Type inference failed: Resulting type is Collection<T> but List<Int> was expected
Unresolved reference: >=
Type mismatch: inferred type is java.util.ArrayList<jet.Int> but java.util.Collection<T> was expected
Type mismatch: inferred type is java.util.Collection<T> but java.util.List<jet.Int> was expected

But I think the problem is also clear without looking at the compiler errors: “fun <T> Collection<T>.select(condition : (T) -> Boolean) : Collection<T>” declares a Collection. So

var selectCollection : Collection<Int> = list.select({ item -> item >= 2})

compiles whereas

var otherSelectList : List<Int> = list.select({ item -> item >= 2})

does not since the compiler can only infer from the type signature from the method declaration and cannot see what type javaClass.newInstance in newInstanceNotNull() will return at runtime. What I am asking myself is why the Collection.filter method does not suffer from this problem… Maybe because it goes with hardcoding ArrayList<T> instead of using javaClass.newInstance(). But I’m not sure, there are quite some other factors that might matter as well.

Have a look at the source :) to see how it works... https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/JLangIterablesLazy.kt#L19

The return type of filter() on Collection is of type List<T>

BTW while surfing the api docs there are source links (right had side) when you hover over a function detail or a snippet of code.

The return type of filter() on Collection is of type List<T>

Right. Stupid me .. Thanx

The return type of filter() on Collection is of type List<T>

That's what the source says but the compiler error says otherwise:

None of the following functions can be called with the arguments supplied: fun <T : jet.Any?>java.util.Iterator<T>.filter(val f : (T) -> jet.Boolean) : java.util.Iterator<T> defined in <java_root>.kotlin fun <T : jet.Any?>jet.Iterable<T>.filter(val predicate : (T) -> jet.Boolean) : java.util.Collection<T> defined in <java_root>.kotlin fun <T : jet.Any?>jet.Array<T>.filter(val predicate : (T) -> jet.Boolean) : java.util.Collection<T> defined in <java_root>.kotlin fun <T : jet.Any?>java.lang.Iterable<T>.filter(val predicate : (T) -> jet.Boolean) : java.util.Collection<T> defined in <java_root>.kotlin.util

And indeed, Collection<T> is the only type annotation that the compiler will accept here:

  var filteredCollection : Collection<Int> = list.filter { item -> item >= 2 }   // compiles anyway

What’s going on?

Yeah, strange ... I was using CE 11.1.1 Build 117.117 and apparently got different compiler errors.

All right, I have another one ... ;-) In the code below I do not really understand why line "-- 1" does not compile. As Bar is a subclass of Foo this should basically be allowed. Interestingly, there is also no error displayed in the IDE at line "--2" also. Do we have the same issue here as in Java where Java treats List<Foo> and List<Bar> as two completely different types and does not look at the class parameter? Just curious in order to understand this.

Regards, Oliver

open class Foo(param : Int) {
  val value = param;
  fun getFoo() : Int {
  return value
  }
}

class Bar(param : Int) : Foo(param) {
  fun getBar() : Int {
  return value
  }
}

fun main(args : Array<String>)
{

  val barList = ArrayList<Bar>
  barList.add(Bar(1))
  barList.add(Bar(2))
  barList.add(Bar(3))

  val filteredBarList : List<Bar> = barList.filter{it.getBar() >= 2} // compiles fine
  val filteredFooList : List<Foo> = barList.filter{it.getBar() >= 2} // does not compile ?! – 1

  filteredFooList.get(0).getFoo();   // compiles fine – 2
  filteredFooList.get(0).getBar();   // does not compile as expected – 3
}

Oops, forgot the compiler errors:

None of the following functions can be called with the arguments supplied:
public final fun <T : jet.Any?>java.util.Iterator<T>.filter(val predicate : (T) -> jet.Boolean) : java.util.Iterator<T> defined in <module>.<root>.kotlin
public final fun <T : jet.Any?>java.lang.Iterable<T>.filter(val predicate : (T) -> jet.Boolean) : java.util.List<T> defined in <module>.<root>.kotlin
public final fun <T : jet.Any?>jet.Iterable<T>.filter(val predicate : (T) -> jet.Boolean) : java.util.List<T> defined in <module>.<root>.kotlin
public final fun <T : jet.Any?>jet.Array<T>.filter(val predicate : (T) -> jet.Boolean) : java.util.List<T> defined in <module>.<root>.kotlin

Something remotely related ... I had a look at what is happening in toSet():

val set = HashSet<Int>()
set.add(1)
set.add(2)
set.add(3)

val selectedSet : Set<Int> = (set.select{ it >= 2 }).toSet()

It goes into this:

public inline fun <in T> java.lang.Iterable<T>.toSet() : Set<T> = to(HashSet<T>())

which calls this:

public inline fun <in T, C: Collection<in T>> java.lang.Iterable<T>.to(result: C) : C {
  for (element in this) result.add(element)
  return result
}

So the toSet() method always copies the elements of the receiver collection into a new set even if the receiver object already is a set and there is hence no conversion to be done. This could be avoided with something like this:

fun <T> Set<T>.toSet() : Set<T>
{
  return this
}

fun <T> Collection<T>.toSet() : Set<T>
{
  return to(HashSet())
}

Just a little thing I wanted to mention.
Cheers, Oliver

The problem here is bad diagnostics.

There actually is an error at the line marked with “1”: you are trying to assign a list of Bar’s to a list of Foo’s, which is not allowed, because the List class is not covariant in its type parameters (Java does not allow you to assign a list of Strings to a list of Objects, and it’s right).

The bad diagnostics are caused by too little intelligence wire into our type inference engine so far. Will improve it soon.

Yeah, and to make it compile, you can say, for example:

``

  val filteredFooList : List<out Foo> = barList.filter{it.getBar() >= 2} // does not compile ?! – 1

“out Foo” is a better version of Java’s “? extends Foo”

Hi Andrey,

thanks for your reply. Think I wrote some fabulous code now that made the compiler break: Compiler terminated with exit code: 2. It is not a compiler error concerning my code, but something inside jetbrains code generation seems to break (judging from the stack trace below). Here is what I did which in this first step still compiles and runs fine:

private inline fun <T> Collection<T>.newInstanceNotNull() : Collection<T>
{
  val newInstance = javaClass.newInstance()
  if(newInstance != null)
  return newInstance
  return ArrayList<T>
}

public inline fun <T> Collection<T>.select(fn : (T) -> Boolean) : Collection<T>
{
  val result = newInstanceNotNull()
  for (item in this) {
  if (fn(item))
           result.add(item)
  }
  return result
}

fun main(args : Array<String>)
{
  val list = ArrayList<Int>()
  list.add(3)
  list.add(7)

  val set = HashSet<Int>()
  set.add(3)
  set.add(7)

  var resultList : List<Int> = (list.select{ it < 12}).toList()
  println(resultList)

  var resultSet : Set<Int> = (set.select{ it < 12}).toSet()
  println(resultSet)
}

Then I thought that this toList and toSet conversion is not too bloody elegenat. So I added these two methods:

public inline fun <T> Set<T>.select(fn : (T) -> Boolean) : Set<T>
{
  return super.select(fn)
}

public inline fun <T> List<T>.select(fn : (T) -> Boolean) : List<T>
{
  return super.select(fn)
}

The test code then becomes:

fun main(args : Array<String>)
{
  val list = ArrayList<Int>()
  list.add(3)
  list.add(7)

  val set = HashSet<Int>()
  set.add(3)
  set.add(7)

  var resultList : List<Int> = list.select{ it < 12}
  println(resultList)

  var resultSet : Set<Int> = set.select{ it < 12}
  println(resultSet)
}

Note, there is no more toList() nor toSet(). When I rebuild the project I get this exception dump (after waiting for quite a while):

java.lang.IllegalStateException: Internal error: (34,18) java.lang.NullPointerException
@BindingContext.java:144
  at org.jetbrains.jet.codegen.CompilationErrorHandler$1.reportException(CompilationErrorHandler.java:27)
  at org.jetbrains.jet.codegen.GenerationState.compileCorrectFiles(GenerationState.java:120)
  at org.jetbrains.jet.compiler.CompileSession.generate(CompileSession.java:161)
  at org.jetbrains.jet.compiler.CompileEnvironment.compileModule(CompileEnvironment.java:156)
  at org.jetbrains.jet.compiler.CompileEnvironment.compileModuleScript(CompileEnvironment.java:107)
  at org.jetbrains.jet.cli.KotlinCompiler.exec(KotlinCompiler.java:144)
  at org.jetbrains.jet.cli.KotlinCompiler.exec(KotlinCompiler.java:90)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  at java.lang.reflect.Method.invoke(Method.java:597)
  at org.jetbrains.jet.plugin.compiler.JetCompiler.execInProcess(JetCompiler.java:276)
  at org.jetbrains.jet.plugin.compiler.JetCompiler.runInProcess(JetCompiler.java:243)
  at org.jetbrains.jet.plugin.compiler.JetCompiler.doCompile(JetCompiler.java:148)
  at org.jetbrains.jet.plugin.compiler.JetCompiler.compile(JetCompiler.java:104)
  at com.intellij.compiler.impl.CompileDriver.compileSources(CompileDriver.java:1931)
  at com.intellij.compiler.impl.CompileDriver.translate(CompileDriver.java:1254)
  at com.intellij.compiler.impl.CompileDriver.doCompile(CompileDriver.java:986)
  at com.intellij.compiler.impl.CompileDriver.doCompile(CompileDriver.java:747)
  at com.intellij.compiler.impl.CompileDriver.access$1000(CompileDriver.java:104)
  at com.intellij.compiler.impl.CompileDriver$8.run(CompileDriver.java:665)
  at com.intellij.compiler.progress.CompilerTask.run(CompilerTask.java:155)
  at com.intellij.openapi.progress.impl.ProgressManagerImpl$TaskRunnable.run(ProgressManagerImpl.java:469)
  at com.intellij.openapi.progress.impl.ProgressManagerImpl$2.run(ProgressManagerImpl.java:178)
  at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:218)
  at com.intellij.openapi.progress.impl.ProgressManagerImpl.runProcess(ProgressManagerImpl.java:169)
  at com.intellij.openapi.progress.impl.ProgressManagerImpl$8.run(ProgressManagerImpl.java:378)
  at com.intellij.openapi.application.impl.ApplicationImpl$6.run(ApplicationImpl.java:434)
  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
  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:662)
  at com.intellij.openapi.application.impl.ApplicationImpl$1$1.run(ApplicationImpl.java:145)
Caused by: Internal error: (34,18) java.lang.NullPointerException
@BindingContext.java:144
  at org.jetbrains.jet.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:156)
  at org.jetbrains.jet.codegen.ExpressionCodegen.visitDotQualifiedExpression(ExpressionCodegen.java:1569)
  at org.jetbrains.jet.codegen.ExpressionCodegen.visitDotQualifiedExpression(ExpressionCodegen.java:58)
  at org.jetbrains.jet.lang.psi.JetDotQualifiedExpression.accept(JetDotQualifiedExpression.java:37)
  at org.jetbrains.jet.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:147)
  at org.jetbrains.jet.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:161)
  at org.jetbrains.jet.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:165)
  at org.jetbrains.jet.codegen.ExpressionCodegen.visitReturnExpression(ExpressionCodegen.java:925)
  at org.jetbrains.jet.codegen.ExpressionCodegen.visitReturnExpression(ExpressionCodegen.java:58)
  at org.jetbrains.jet.lang.psi.JetReturnExpression.accept(JetReturnExpression.java:38)
  at org.jetbrains.jet.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:147)
  at org.jetbrains.jet.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:161)
  at org.jetbrains.jet.codegen.ExpressionCodegen.generateBlock(ExpressionCodegen.java:853)
  at org.jetbrains.jet.codegen.ExpressionCodegen.visitBlockExpression(ExpressionCodegen.java:722)
  at org.jetbrains.jet.codegen.ExpressionCodegen.visitBlockExpression(ExpressionCodegen.java:58)
  at org.jetbrains.jet.lang.psi.JetBlockExpression.accept(JetBlockExpression.java:45)
  at org.jetbrains.jet.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:147)
  at org.jetbrains.jet.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:161)
  at org.jetbrains.jet.codegen.ExpressionCodegen.returnExpression(ExpressionCodegen.java:936)
  at org.jetbrains.jet.codegen.FunctionCodegen.generatedMethod(FunctionCodegen.java:232)
  at org.jetbrains.jet.codegen.FunctionCodegen.generateMethod(FunctionCodegen.java:73)
  at org.jetbrains.jet.codegen.FunctionCodegen.gen(FunctionCodegen.java:63)
  at org.jetbrains.jet.codegen.NamespaceCodegen.generate(NamespaceCodegen.java:71)
  at org.jetbrains.jet.codegen.GenerationState.generateNamespace(GenerationState.java:131)
  at org.jetbrains.jet.codegen.GenerationState.compileCorrectFiles(GenerationState.java:114)
  … 33 more
Caused by: java.lang.NullPointerException
  at org.jetbrains.jet.lang.resolve.BindingContext$3.normalize(BindingContext.java:144)
  at org.jetbrains.jet.lang.resolve.BindingContext$3.normalize(BindingContext.java:125)
  at org.jetbrains.jet.util.slicedmap.Slices$SliceWithOpposite.makeKey(Slices.java:176)
  at org.jetbrains.jet.util.slicedmap.SlicedMapImpl.get(SlicedMapImpl.java:85)
  at org.jetbrains.jet.lang.resolve.BindingTraceContext.get(BindingTraceContext.java:79)
  at org.jetbrains.jet.lang.resolve.BindingTraceContext$1.get(BindingTraceContext.java:47)
  at org.jetbrains.jet.codegen.ExpressionCodegen.generateThisOrOuter(ExpressionCodegen.java:1436)
  at org.jetbrains.jet.codegen.StackValue$ThisOuter.put(StackValue.java:1018)
  at org.jetbrains.jet.codegen.StackValue$CallReceiver.genReceiver(StackValue.java:1155)
  at org.jetbrains.jet.codegen.StackValue$CallReceiver.put(StackValue.java:1133)
  at org.jetbrains.jet.codegen.ExpressionCodegen.invokeMethodWithArguments(ExpressionCodegen.java:1353)
  at org.jetbrains.jet.codegen.ExpressionCodegen.invokeFunction(ExpressionCodegen.java:1289)
  at org.jetbrains.jet.codegen.ExpressionCodegen.visitCallExpression(ExpressionCodegen.java:1255)
  at org.jetbrains.jet.codegen.ExpressionCodegen.visitCallExpression(ExpressionCodegen.java:58)
  at org.jetbrains.jet.lang.psi.JetCallExpression.accept(JetCallExpression.java:45)
  at org.jetbrains.jet.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:147)
  … 57 more

I was a bit surprised that f.ex.

public inline fun <T> Set<T>.select(fn : (T) -> Boolean) : Set<T>
{
  return super.select(fn)
}

compiled fine. I thought I would have to write something like this to make it compile:

public inline fun <T> Set<T>.select(fn : (T) -> Boolean) : Set<T>
{
  return super.select(fn).toSet()
}

with toSet being:

public inline fun <T> Set<T>.toSet() : Set<T>
{
  return this
}

Anyway, I get the same compiler dump with this approach as well. Maybe someone could spare a little time to have a look into this. Would be nice if the old Smalltalk yourself trick (method returns self as in the method just above this paragraph) could be applied here.

Kind regards, Oliver

Please, file an issue in uor bug tracker. Thanks.

Okay, I just filed the isse: http://youtrack.jetbrains.com/issue/KT-1851

There is something else I wanted to ask, but don’t dare to open up a new topic for. But maybe someone competent will read this. Question is: “How do you pronounce Kotlin?”. I used to pronounce it like “Kootliiin” which is what someone of my mother tounge would say if not be told otherwise. Now I have a co-worker of Russion origin and he pronounced it with a very short “o” and a short “i”. Now I’m confused …