4

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?

0

3 Answers 3

5

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
Sign up to request clarification or add additional context in comments.

3 Comments

It's correct, but just for some primitive types (Byte, Float, Double, Int, Long , Char and ,Boolean). Not String. Your second example can be written an val arr = IntArray(N){2}
@PauloBuchsbaum For reference arrays, use something like val arr = Array(N) { "" } or val arr = Array<String?>(N) { null }
Yes, but my point is allow the programmers choice the array size in declaration type part and not inside initialization part. It protects the programmers against wrong assigments related to array size.
1

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.

2 Comments

I know that array bounds are checked in runtime, but in another point. When you assign an array longer than what is projected, there is no possible check in Kotlin. Evidently when trying to use a component outside the existing indexes, every language (practically) will give error. Old languages could be make a compiler check of size arrays as long the the used sizes was constants (therefore known in compiler time)
Imagine a structure with an array of 3D points arrays. Unless you define 3D with a class there is no way to define in compiler time that each point has length 3.
1

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
}

2 Comments

Yes, I know, but I believe that would be useful choice for programmers select the size in the type and not through initialization. Size initialization in the type allow checking bound violation in runtime. It could by part of type definition, avoiding logical errors. It reallly has happened this in my project.
I see. I've edited my answer to add some possible solutions

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.