1

i want to create a closure where it take all the Boolean expression and methods, gives the final result something like this

  myAnd{
    23<34
    false
    someFunction() //returns true
    }

so the answer will be false

The solution i came with is this

fun myAnd(vararg flags: Boolean) = flags.all { it }

myAnd(true , false ,someFunction())

but this solution won't give the power of short circuiting while using and operator

aman5319
  • 662
  • 5
  • 16

2 Answers2

3

Using blocks to implement short-circuiting and

fun someFunction() = true

fun and(vararg parameters: ()->Boolean): Boolean {
    return parameters.all { it() }
}

fun main(args: Array<String>) {
    and (
            {23<34},
            {false},
            ::someFunction
    )
}

This works by passing in each predicate as a block, which means that they can be evaluated one by one, and if any of them returns false then all will return false immediately, short-circuiting the rest of them.

jrtapsell
  • 6,719
  • 1
  • 26
  • 49
  • Thank you for the answer but is there any way to make it idiomatic by using closure rather than passing lambdas as an argument of the method – aman5319 May 11 '18 at 21:21
  • This _is_ the more idiomatic solution. You really want 3 closures here, not 1, because using the single closure like this is equivalent to `{ someFunction() }`: it just evaluates the first 2 lines and ignores their values. – Alexey Romanov May 12 '18 at 08:53
2

I can think of a quick solution that enables the following use:

val boolResult: Boolean = myAnd {
    + (23 < 34)
    + false
    + someFunction() //returns true
}

Here's the relevant code:

fun myAnd(bb: BooleanBuilder.() -> Unit) = BooleanBuilder().apply { bb() }.result

class BooleanBuilder {
    var bools = listOf<Boolean>()
    operator fun Boolean.unaryPlus() {
        bools += this
    }

    fun result() = bools.all { it }
}

Explanation: It's a lightweight example of a custom DSL. The interesting part of this is BooleanBuilder.() -> Unit, a function literal with receiver, so that I can pass a lambda that's in the scope of a BooleanBuilder (lambda's receiver). This is necessary to use the member extension Boolean.unaryPlus that again enables the use of + boolean as shown.

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196