Search code examples
groovyclosuresfirst-order-logic

Recreating the if/else in groovy: giving multiple closures arguments to a function


While trying to reinvent the if/else syntax with closures in groovy, I couldn't manage to make it work. I think putting multiple closures outside the parenthesis is not permitted, but it could be something else.

If it isn't permitted, how would you reproduce the if/else syntax? This is a thought experiment, so don't tell me about the the inefficiency of this implementation.

My code:

void ifx(boolean condition, Closure action){
  ["${true.toString()}": action].get(condition.toString(), {})()
}

void ifx(boolean condition, Closure action, Closure elsex){
  ["${true.toString()}": action, "${false.toString()}": elsex].get(condition.toString())()
}

void elsex(Closure action){
    action()
}

ifx(1==2){
    println("1")
} ifx(1==3){
    println("2")
} elsex{
    println("3")
}

Error message:

java.lang.NullPointerException: Cannot invoke method ifx() on null object


Solution

  • Something along these lines works:

    updated with closures to avoid global state:

    def ifx( outerCondition, outerBlock ) {
      boolean matched = false
      def realIfx
      realIfx = { condition, block ->
        if (condition) {
          matched = true
          block()
        }
        [ifx: realIfx, elsex: { elseBlock -> if(!matched) elseBlock() }]
      }
    
      realIfx outerCondition, outerBlock
    }
    

    And some testing:

    def result
    
    ifx(1 == 2) {
      result = 1
    } ifx(1 == 3) {
      result = 2
    } elsex {
      result = 3
    }
    
    assert result == 3
    result = null
    
    
    ifx (1 == 2) {
      result = 1
    } ifx (2 == 2) {
      result = 2
    } elsex {
      result = 3
    }
    
    assert result == 2
    result = null
    
    ifx (true) {
      result = 1
    } ifx (2 == 1) {
      result = 2
    } elsex {
      result = 3
    }
    
    assert result == 1