Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

break or continue jump across class boundary kotlin

Tags:

android

kotlin

is anyone facing this problem. break or continue jump across class boundary kotlin

this problem appears when i am going to use break or continue. inside lambda with receiver i create 'letIn'

lambda with receiver code

fun letIn(componentName: String?, values: List<LifeService.Value?>?,
       body: (String, List<LifeService.Value?>) -> Unit) {
  if (!TextUtils.isEmpty(componentName) && (values != null && values.isNotEmpty())) {
     body(componentName!!, values)
  } 
}

this sample code for it.

for (option in 0 until optionsSize) {
    val component = optionsGroup?.options?.get(option)
    component?.let {
        with(component) {
            letIn(presentation, values, { componentName, values ->
                if (componentName == LifeComponentViewType.CHECKBOX) {
                    letIn(transformCheckBoxValues(optionsGroup), { data ->
                        dataSource?.push(componentName, ComponentDataCheckBoxCollection(name, data))
                        view.buildComponent(componentName)
                         // break or continue didnt work
                    })
                } else {
                    dataSource?.push(componentName, ComponentDataCollection(name, values))
                    view.buildComponent(componentName)
                }
            })
        }
    }
 }

because above code didnt work so i use imperative way.

for (option in 0 until optionsSize) {
val component = optionsGroup?.options?.get(option)
        if (component != null) {
            val presentation: String? = component.presentation
            val values = component.values
            if (!TextUtils.isEmpty(presentation)) {
                if (presentation == LifeComponentViewType.CHECKBOX) {
                    val data = transformCheckBoxValues(optionsGroup)
                    if (data.isNotEmpty()) {
                        dataSource?.push(presentation, ComponentDataCheckBoxCollection(optionsGroup.name, data))
                        view.buildComponent(presentation)
                        return
                    }
                } else {
                    dataSource?.push(presentation!!, ComponentDataCollection(component.name, values))
                    view.buildComponent(presentation!!)
                }
            } else {
                return
            }
        }
    }

does anyone have suggestions?

UPDATE i've been fix this issue by inlining high order function.

like image 836
raditya gumay Avatar asked Nov 09 '17 02:11

raditya gumay


1 Answers

(Other coding errors aside) You are seeing the error because inside your lambda, you cannot use break or continue to jump out of the lambda to the nearest loop. Instead, you can use a qualified return to jump out of the lambda to a label.

Referring to the language reference

The return-expression returns from the nearest enclosing function, i.e. foo. (Note that such non-local returns are supported only for lambda expressions passed to inline functions.) If we need to return from a lambda expression, we have to label it and qualify the return:

(Emphasis mine)

Your second example shows that you want your lambdas to do a non-local return from the enclosing function. Therefore, you do not need to qualify your return, but your function letIn must be declared inline (else you can only do a local, qualified return).

inline fun letIn(componentName: String?, values: List<LifeService.Value?>?,
       body: (String, List<LifeService.Value?>) -> Unit) {
  if (!TextUtils.isEmpty(componentName) && (values != null && values.isNotEmpty())) {
     body(componentName!!, values)
  } 
}

... or if you want it to have receivers...

inline fun String?.letIn(values: List<LifeService.Value?>?,
                         body: String.(List<LifeService.Value?>) -> Unit) {
    if (!TextUtils.isEmpty(this) && (values != null && values.isNotEmpty())) {
        this!!.body(values)
    }
}

When you declare letIn as inline, then you can place return in your lambdas without the compiler complaining. Your function would not need to be inline if your lambdas are only doing local returns, but it would need to have a qualified return (for example return@letIn).

Your first example would then look like this...

for (option in 0 until optionsSize) {
    val component = optionsGroup?.options?.get(option)
    component?.let {
        with(component) {
            presentation.letIn(values, { values ->
                if (this == LifeComponentViewType.CHECKBOX) {
                    this.letIn(transformCheckBoxValues(optionsGroup), { data ->
                        dataSource?.push(this, ComponentDataCheckBoxCollection(this, data))
                        view.buildComponent(this)
                        return //returns from function
                    })
                } else {
                    dataSource?.push(this, ComponentDataCollection(name, values))
                    view.buildComponent(this)
                    return  //returns from function
                }
            })
        }
    }
}

Lastly, note that if you wanted to jump out of the lambda early, but continue an outer loop as in:

fun test1() {
    val list = listOf("a", "b", "c")
    val optionsSize = 2
    for(i in 0..optionsSize) loop@ {
        println("calliing list.forEach")
        list.forEach lit@ {
            if(it == "a") return@lit
            if(it == "c") return@loop
            println(it)
        }
    }
}

It won't work. Intelli-sense doesn't complain about it, but the compiler throws an internal error. But you can convert the outer loop to a lambda, and it does work...

fun test() {
    val list = listOf("a", "b", "c")
    val optionsSize = 2
    (0..optionsSize).forEach() loop@ {
        println("calliing list.forEach")
        list.forEach lit@ {
            if(it == "a") return@lit
            if(it == "c") return@loop
            println(it)
        }
    }
}

Again, this only works if the function to which the lambda is passed is declared inline (like forEach is declared inline).

like image 160
Les Avatar answered Sep 21 '22 21:09

Les