kotlinfunction-reference

in kotlin how to put function reference in an array


Having class member function like:

private fun getData1(uuid:String): IData? {
    ...
}
private fun getData2(uuid:String): IData? {
    ...
}
private fun getData3(uuid:String): IData? {
    ...
}

and would like to put in a function reference array:

var funArray = ArrayList<(uuid: String) -> IData?> (
     this::getData1, 
     this::getData2, 
     this::getData3)

it does not compile:

None of the following functions can be called with the arguments 
supplied: 
public final fun <E> <init>(): kotlin.collections.ArrayList<(uuid: String) -> IData?> /* = java.util.ArrayList<(uuid: String) -> IData?> */ defined in kotlin.collections.ArrayList ...

if do:

var funArray: ArrayList<(uuid: String) -> IData?> = ArrayList<(uuid: String) -> IData?>(3)

funArray[0] = this::getData1 //<== crash at here
funArray[1] = this::getData2
funArray[2] = this::getData3

crash with exception

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

How to put function reference in an array?


Solution

  • The first attempt fails because ArrayList doesn't have a constructor taking (a variable argument list of) values.

    You can get pretty much the same effect by replacing ArrayList with listOf() (or, if you need mutability, mutableListOf()), as that does take a vararg list:

    var functions = listOf<(uuid: String) -> IData?>(
        this::getData1, 
        this::getData2, 
        this::getData3)
    

    That's perhaps the most natural solution.  (However, mutableListOf() is only guaranteed to return a MutableList implementation; it may not be an ArrayList.)

    The second attempt fails because it's constructing an empty list.

    (The ArrayList constructor it uses takes a parameter called initialCapacity; it ensures that the list could take at least 3 elements without needing to reallocate its arrays, but its initial size is zero.)

    Perhaps the confusion is because although you say you ‘would like to put in a function reference array’, you're creating a List, not an Array.

    (The ArrayList class is an implementation of the List interface which happens to use an array internally.  This follows the Java convention of naming implementation classes as <Implementation><Interface>.)

    If you need to create an actual array, you could use arrayOf() in the first example:

    var functions = arrayOf<(uuid: String) -> IData?>(
        this::getData1, 
        this::getData2, 
        this::getData3)
    

    Lists are probably used more widely than arrays in Kotlin, as they're more flexible.  (You can choose between many different implementations, with different characteristics.  They work better with generics; for example, you can create a List of a generic type.  You can make them immutable.  And of course if they're mutable, they can grow and shrink.)

    But arrays have their place too, especially if performance is important, you need to interoperate with code that uses an array, and/or the size is fixed.