Search code examples
kotlindata-structuresdynamic-arrays

Custom print() of DynamicArray in Kotlin prints unexpected result


I have a simple scenario where I have Kotlin class DynamicArray.kt:

class DynamicArray(size: Int) {

    private var numArray: IntArray
    private var count: Int = 0

    init {
        if (size <= 0)
            throw IllegalArgumentException("Invalid value for array size")    
        numArray = IntArray(size)
    }

    fun insert(item: Int) {
        if (numArray.size == count){

            // Create newArray with double size
            val newArray = IntArray(count * 2)

            // copy old to new
            for ((index, i) in numArray.withIndex()){
                newArray[index] = i
            }

            // assign newArray to old
            numArray = newArray

        }
        numArray[count++] = item
    }

    fun print(): String {
        val arrayAsString = StringBuilder()
        arrayAsString.append("[")
        for ((index, i) in numArray.withIndex()){
            arrayAsString.append(i)
            if (index != (count - 1)){
                arrayAsString.append(", ")
            }
        }
        arrayAsString.append("]")
        return arrayAsString.toString()
    }
}

And a simple Main.kt class which only have:

fun main(args: Array<String>) {
    val array = DynamicArray(3)

    array.insert(1)
    array.insert(2)
    array.insert(3)

    println(array.print())

}

The above code works perfect when size of DynamicArray and items are eqaul it prints

[1, 2, 3]

but when we insert more items the initial size e.g:

fun main(args: Array<String>) {
    val array = DynamicArray(3)

    array.insert(1)
    array.insert(2)
    array.insert(3)
    array.insert(4)

    println(array.print())

}

it prints weird values like:

[1, 2, 3, 40, 0, ]

Update

if I change the print method to:

fun print(): String {
        return numArray.contentToString() // using built-in method
}

it still prints :

[1, 2, 3, 4, 0, 0]

Un-able to figure out what is causing this issue.


Solution

  • First, let's look at how you can find out where the problem is.

    There are many techniques for debugging, but by far the most useful in general is simply printing stuff out.  In order to narrow down where the problem is, it's really really really useful to be able to see the state of the program — in this case, the contents of the DynamicArray — at each point.

    What you'd like to be able to do is to add a line such as:

    println("Point A: $array")
    

    …before and after each call to insert().  The trouble is that that just prints something like:

    Point A: DynamicArray@63947c6b
    

    …which is because the DynamicArray doesn't override toString().  You could instead call your print() method — but you don't know whether the bug is in there or not.

    If DynamicArray were a data class, you'd get a shiny toString() implementation automatically.  But this class wouldn't really fit as a data class (and would need lots of other changes).  But there's nothing stopping you from writing your own, e.g.:

    override fun toString() = "DynamicArray(count=$count, numArray=[${numArray.joinToString()}])"
    

    With that in place, you can add lots of debugging output.  For example:

    Start: DynamicArray(count=0, numArray=[0, 0, 0])
    Inserted 1: DynamicArray(count=1, numArray=[1, 0, 0])
    Inserted 2: DynamicArray(count=2, numArray=[1, 2, 0])
    Inserted 3: DynamicArray(count=3, numArray=[1, 2, 3])
    Inserted 4: DynamicArray(count=4, numArray=[1, 2, 3, 4, 0, 0])
    Inserted 5: DynamicArray(count=5, numArray=[1, 2, 3, 4, 5, 0])
    [1, 2, 3, 4, 50, ]
    

    From that, it becomes a lot clearer where the problem is!  You can see that both count and numArray are getting set correctly. So the problem must be in your print() method.

    I'm not going to give the final solution here, as I think it would help you much more to work out the rest yourself; I hope this has given you enough of a start to do that. (If you want a hint, consider how many numbers it prints, and where it puts the commas.)