Is array declaration in Kotlin with size possible just with initialization?

Viewed 3515

I didn't find how to declare in Kotlin an array with predefined size without initializate it.

This is OK:

lateinit var v:Array<Int>

But I guess that one cannot put a size specification in array type.

If one needs to specify a size. one have to do:

var v2:Array<Int> = Array<Int>(2){5}

In this case, all elements of the vector are equal to 5

Below there is a example with classes and arrays:

data class But(
    val fufo: Int=0,
    val tp: Int = 1 
)  
typealias  ArBut = Array<But>
data class CArray (
   var arrayC: ArBut = ArBut(2){But()}
)    
val a =   CArray(arrayOf(But(2,2),But(5,4),But(3,3)))
println(a.arrayC[2])

It works! The interesting part is that how the initialization is not part of type, you can put arrays of any size in the class without bounding check. It would be different if the size was part of type spec.

Now an exemple, using matrix. Notice that the syntax is a little bit intricate.

data class CMatr (
   val matrC: Array<ArBut>  = Array<ArBut>(2){ArBut(0){But()}}
)    
 val m =   CMatr(arrayOf( arrayOf(But(2,2),But(5,4)),   
         arrayOf(But(-2,2),But(3,4)), arrayOf(But(1,1),But(5,3))  ))
 println(m.matrC[2][1])  // Also works! 

Is it impossible put size in array type specification or I'm missing something?

3 Answers

for primitive types :

this is how you do it. instead of using kotlin built-in functions like intArrayOf(args...) you use the constructor for IntArray

here is the example :

// Array of integers of a size of N
val arr = IntArray(N)

// Array of integers of a size of N initialized with a default value of 2
val arr = IntArray(N) { 2 }

for reference types :

for reference type objects you can do

val cars: Array<Car?> = arrayOfNulls(N) 
//returns an array of nullable Car objects with null values and size of N

and if you want to an array of non null objects you need to initialize them when creating array

val cars: Array<Car> = Array<Car>(5){ Car() } 
//returns an array of non nullable car objects that has been initialized 
//with the method you provided in this case Car constructor with size of N

For your example, with the Butclass, you could use:

var arrayC: Array<But?> = arrayOfNulls(2) // no initialization required

or:

var arrayC: Array<But> = Array<But>(2){But()} // initialization required

But either way will not forbbid you of creating a new instance of a bigger array and assign it to the variable.

EDIT

The way I see it, there are two approaches to solve this.

The first would be to declare your array property as a var and test the assignement in your setter:

class Test {
    var array: Array<Int> = Array(3){0}
        set(value) {
            if(value.size > 3)
                throw IllegalArgumentException("The array size cannot be bigger than 3")

            field = value
        }
}

fun main(args: Array<String>) {
    val test = Test()
    test.array = arrayOf(0, 1, 2) // Ok
    test.array = arrayOf(0, 1, 2, 3) // throws IllegalArgumentException

}

Or, if you want to deal with it at compile time, you can make your property final and initialize it with the size you want.

class Test {
    val array: Array<Int> = Array(3){0}
}

fun main(args: Array<String>) {
    val test = Test()

    for (i in 0..2) // Ok
        test.array[i] = i

    for (i in 0..3) // throws ArrayIndexOutOfBoundsException
        test.array[i] = i

    test.array = arrayOf(0, 1, 2, 3) // compile time error: Val cannot be reassigned
}

Yes, array size is not part of its type in Kotlin and there's no way to make it a part. This isn't specific to arrays; types can't depend on values in any way in Kotlin.

Size initialization in the type allow checking bound violation in runtime.

Array bounds are always checked at runtime on JVM. Even if a compiler wanted not to do it, it can't.

Related