Control flow conditions through lambdas

Going down the functional rabbit hole, I think it would be nice to be able to have the jump condition of control flow be determined via a lambda.

Rather than declaring a ‘condition variable’, instead have it be the last line of a lambda, just like a if/else statement or call to .let.

This is the piece of code that got me thinking about this:

// val fis: FileInputStream = ...
var length: Int // Keep track of the number of read 
val buf = ByteArray(1024)
while (fis.read(buf).also { length = it } > 0){
    processBytes(buf, length)
}

This is the functionally I’m going for:

val buf = ByteArray(1024)
while { fis.read(buf).also { length -> processBytes(buf, length) } > 0 } // doesn't work

For the following demonstates what I’m going for

fun during(predicateBlock: () -> Boolean) { while (predicateBlock()) { } }

// now we can just have the lambda return the condition, no declaring a 'useless' variable
during { fis.read(buf).also { processBytes(buf, length) } > 0 }
// technically this is equivalent to a do {} while (predicateBlock()) however

Thoughts/Opinions?

Hi @morgan.trench,
I’m not really convinced of your proposal.

I share below my personal considerations, please correct me if I wrong.

You propose during { someBlock() } instea of while (someBlock());, but I don’t see a great enhanchement.

Your example while (fis.read(buf).also { length = it } > 0) is not really simple - at least for me.

Your functional rabbit leaves in the top hat some non-functional side effects, please reconsider your example.

Lastly ask yourself if something like fun InputStream.forEachByteArray(block: (ByteArray) -> Unit) is enough.

Hi @fvasco

You are correct that it isn’t a great enhancement, it’s only meant to be a minor convenience to avoid declaring (what I feel are) unnecessary variables and eliminate the condition.

I’m not sure how to respond to the point on side effects.

My example is a little bit specific to my current use-case, hopefully the following one can make it clearer:

Imagine a function that is intended to be called repeatedly, and its return value can be used to determine whether or not to continue calling the function. Here I use taking a turn in a game for context, an example game might be Russian roulette (except you can back out).

fun takeTurn(): Double = // Take a turn, return the estimated chances of winning afterwards

Using a traditional while loop structure:

val giveUpThreshold = 0.5
var chanceOfWinning: Double
fun playGameOne(){
    while( takeTurn().also{ chanceOfWinning = it } > giveUpThreshold) {}
}

Using a traditional do while loop structure

val giveUpThreshold = 0.5
var chanceOfWinning: Double
fun playGameTwo(){
    do {
        chanceOfWinning = takeTurn()
    } while ( chanceOfWinning > giveUpThreshold)
}

Using a proposed ‘do while’ where the condition is the last line of the ‘do’ block:

val giveUpThreshold = 0.5
fun playGameThree(){
    // example of proposal, no need for 'chanceOfWinning' to store jump/branch criteria
    // obviously this currently produces an error
    do {
        takeTurn() > giveUpThreshold
    } // while(result of takeTurn() > giveUpThreshold)
}

That last one (playGameThree()) is an example of where i think such an capability would be of use. The contents of the lambda need not be one line, the lambda could be the body of takeTurn for example.

Hopefully that makes sense. Thank you for taking the time to read this :slight_smile:

Hi @morgan.trench,
I understand your point.

Are you considered the currently working syntax:

val giveUpThreshold = 0.5
fun playGameThree(){
    while(takeTurn() > giveUpThreshold) ; // please note semicolon, you can replace it with "{ }" or "Unit"
}

For my point of view your consideration is valid, but not really useful to be included in Kotlin standard library.