Why I can't apply value inside while loop?


#1

Hey, I’d like to know why kotlin doesn’t support this code:

I’m using Android Studio 3.1.2 along with Kotlin 1.2.41
Thanks.


#2

Because “assignments are not expression”, they are statements, like variable declarations or for/while loop.


#3

The Kotlin team decided against it for a few reasons I think. In most cases it is just considered bad style and it also makes code harder to read. Yes your example is the one valid place where this kind of feature would be pretty handy, but they decided against it still, because only a small numbers of libraries would actually use something like this and it’s not worth adding an new feature to the language just for that.
Also there is a massive discussion about this here


#4

I recently encountered the similar problem. The solution was rather elegant:

do{
  val bytesRead = stream.read(buffer)
} while(byteRead != -1)

By the way, please do not use screenshots to present the code.


#5

An alternative option is to use also

var bytesRead:Int =0
while(stream.read(buffer).also { bytesRead = it } >=0) {
  out.write(buffer, 0, bytesRead)
}

I agree it isn’t very pretty, perhaps the best way is to make it into some sort of inline function that encapsulates the ugliness of whatever code you end up using.


#6

Or even maybe custom loop function can be useful

inline fun InputStream.whileReadBytes(array: ByteArray, block: (Int) -> Unit) {
    while (true) {
        val count = read(array)
        if (count < 0) break
        block(count)
    }
}

fun copy(input: InputStream, output: OutputStream) {
    val bytes = ByteArray(512)
    input.whileReadBytes(bytes) { count ->
        output.write(bytes, 0, count)
    }
}

#7

First off for the simple example of copying from an input stream to an OutputStream there is already the InputStream.copyTo extension method in the standard library.

But to address this code suggestion, I would reverse that because I always feel dirty creating local variables and always try to find ways to avoid them:

inline fun ByteArray.whileReadBytes(input: InputStream, block: ByteArray.(Int) -> Unit) {
    while (true) {
        val count = input.read(this)
        if (count < 0) break
        this.block(count)
     }
}

fun copy(input: InputStream, output: OutputStream) {
    ByteArray(512).whileReadBytes(input) { output.write(this, 0, it) }
}

#8

I think this is the best solution in terms of length, I will use it, thanks.


#9

Kotlin stdlib already has a copyTo function:

input.copyTo(output, bufferSize = 512)

#10

Which I said in the first sentence of my post. But I assumed that it was just a simple example and the problem the OP was trying to solve was something more complicated.

But the point of my post was focusing on the design of the previously suggested whileReadBytes method which can be used for other things than copying to an output stream.