Andrei K.
Andrei K.

Reputation: 580

Is it possible to init a variable in the while condition body for Kotlin?

In the code below:

    var verticesCount: Int // to read a vertices count for graph

    // Reading until we get a valid vertices count.
    while (!Assertions.checkEnoughVertices(
            verticesCount = consoleReader.readInt(null, Localization.getLocStr("type_int_vertices_count"))))
        // The case when we don't have enough vertices.
        println(String.format(Localization.getLocStr("no_enough_vertices_in_graph"),
                              Assertions.CONFIG_MIN_VERTICES_COUNT))

    val resultGraph = Graph(verticesCount)

we are getting next error on the last line:

Error:(31, 33) Kotlin: Variable 'verticesCount' must be initialized

Assertions.checkEnoughVertices accepts a safe type variable as an argument (verticesCount: Int), so it's impossible for verticesCount to be uninitialized or null here (and we're getting no corresponding errors on those lines).

What's going on on the last line when already initialized variable becomes uninitialized again?

Upvotes: 4

Views: 7025

Answers (2)

Zordid
Zordid

Reputation: 10469

Well, technically it is possible to assign values to variables in the while condition - and anything else you might want to do there, too. The magic comes from the also function:

Try this: (excuse the completely useless thing this is doing...)

var i = 10
var doubleI: Int
while ((i * 2).also { doubleI = it } > 0) {
    i--
    println(doubleI)
}

Any expression can be "extended" with "something to do" by calling also which takes the expression it is called upon as the it parameter and executes the given block. The value also returns is identical to its caller value.

Here's a very good article to explain this and much more: https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84

Upvotes: 5

Alexander Udalov
Alexander Udalov

Reputation: 32826

The syntax you've used denotes a function call with named arguments, not the assignment of a local variable. So verticesCount = is just an explanation to the reader that the value which is being passed here to checkEnoughVertices corresponds to the parameter of that function named verticesCount. It has nothing to do with the local variable named verticesCount declared just above, so the compiler thinks you've still to initialize that variable.

In Kotlin, the assignment to a variable (a = b) is not an expression, so it cannot be used as a value in other expressions. You have to split the assignment and the while-loop condition to achieve what you want. I'd do this with an infinite loop + a condition inside:

var verticesCount: Int

while (true) {
    verticesCount = consoleReader.readInt(...)
    if (Assertions.checkEnoughVertices(verticesCount)) break

    ...
}

val resultGraph = Graph(verticesCount)

Upvotes: 9

Related Questions