Rust allows a kind of do-while loop eg:
So the C style:
do {
something();
} while (test());
Can be written in Rust as:
while {
something();
test()
}{}
However there is a problem using break in this case:
So this C style:
do {
if (something()) {
break;
}
} while (test());
Can't be written in Rust as:
while {
if (something()) {
break;
}
test()
}{}
Fails to compile with cannot break outside of a loop.
Is there a way to break out of this form of while loop?
Note 1) the reason to use:do {...} while test() flow control instead ofwhile test() {...} is in this case test() will be false when entering the loop initially.
Note 2) When using while {...} flow control: calling continue in the body of the code will skip the break check at the end.
See related question: How to wrap a do-while style loop in a macro, maintaining 'continue' flow control?
As mentioned in the comments, it is important to understand how this pattern works. It is not a special form of while, it simply abuses the loop test to do things normally done in the body. Since break and continue don't belong in the loop test (unless the loop is part of another loop, in which case they will compile, but break/continue the outer loop), Rust rejects them.
A straightforward way to emulate break with the above pattern is by moving the test code to a closure from which one can exit with return:
while (|| {
if something() {
return false // break
}
test()
})() {}
continue can be emulated the same way, simply by returning true from the closure.
It would probably possible to make the intention clearer if this were expressed as a macro.
You are overthinking this.
Let's build a truth table:
+-------------+--------+--------+
| something() | test() | Result |
+-------------+--------+--------+
| true | true | stop |
+-------------+--------+--------+
| true | false | stop |
+-------------+--------+--------+
| false | true | go on |
+-------------+--------+--------+
| false | false | stop |
+-------------+--------+--------+
Thus, this can be written as:
while !something() && test {}
There is no need for a break.
A valid solution close to your proposition could be:
while {
// bloc
test()
} {
// break conditions belonging here
if (something()) {
break;
}
}
Some remarks:
The first bracket has to be an expression, Rust allows the user to write statements before it and the whole bloc with test() is considered as an expression but there are some limitations as you have pointed out
A well built loop generally avoids break and continue statements, this solution has the advantage to separates the loop-flow logic in the first bracket from the added control logic exceptionally used in the second bracket as it were parameters of the loop outside of it
this time something() is called after test(), it means that it won't be able to break the first iteration of the loop
With rust you can label a loop when you declare it and use the label to break the loop later:
'mylabel: loop {
something();
if test() { break 'mylabel; }
}
Related
I want to check if the result from a request is having any issue. I categorize it into two: i) server error, ii) something else that is not a success. The third category is, result actually being a success. However, in the third category, I don't want to do anything.
So, my desirable code is:
if res.status().is_server_error() {
panic!("server error!");
} else if !(res.status.is_success()){
panic!("Something else happened. Status: {:?}", res.status());
} else{
pass;
}
I am aware of other ways to achieve this result: using match, ifs instead of if else if. But I wanted to learn what is the corresponding keyword of pass, like we have in Python. My aim is: if result is successful, just move along, if not, there are two ways to handle that panic.
Behold!
if predicate {
do_things();
} else {
// pass
}
Or even better
if predicate {
do_things();
} // pass
Or as I’ve recently taken to calling it the implicit + pass system
if predicate {
do_things();
}
In all seriousness there is no pass and no need for a pass in rust. As for why it exists in python, check out this answer
Python needs pass because it uses indentation-based blocks, so it requires some syntax to "do nothing". For example, this would be a syntax error in a Python program:
# syntax error - function definition cannot be empty
def ignore(_doc):
# do nothing
count = process_docs(docs, ignore) # just count the docs
The ignore function has to contain a block, which in turn must contain at least one statement. We could insert a dummy statement like None, but Python provides pass which compiles to nothing and signals the intention (to do nothing) to the human reader.
This is not needed in Rust because Rust uses braces for blocks, so one can always create an empty block simply using {}:
// no error - empty blocks are fine
fn ignore(_doc: &Document) {
// do nothing
}
let count = process_docs(docs, ignore); // just count the docs
Of course, in both idiomatic Python and Rust, one would use a closure for something as simple as the above ignore function, but there are still situations where pass and empty blocks are genuinely useful.
"When you've found the treasure, stop digging!"
I'm wanting to use more functional programming in Groovy, and thought rewriting the following method would be good training. It's harder than it looks because Groovy doesn't appear to build short-circuiting into its more functional features.
Here's an imperative function to do the job:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
String shortestUniqueName(String nameToShorten) {
def currentLevel = 1
String shortName = ''
def separator = '/'
while (fullyQualifiedNames.findAll { fqName ->
shortName = nameToShorten.tokenize(separator)[-currentLevel..-1].join(separator)
fqName.endsWith(shortName)
}.size() > 1) {
++currentLevel
}
return shortName
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
It scans a list of fully-qualified filenames and returns the shortest unique form. There are potentially hundreds of fully-qualified names.
As soon as the method finds a short name with only one match, that short name is the right answer, and the iteration can stop. There's no need to scan the rest of the name or do any more expensive list searches.
But turning to a more functional flow in Groovy, neither return nor break can drop you out of the iteration:
return simply returns from the present iteration, not from the whole .each so it doesn't short-circuit.
break isn't allowed outside of a loop, and .each {} and .eachWithIndex {} are not considered loop constructs.
I can't use .find() instead of .findAll() because my program logic requires that I scan all elements of the list, nut just stop at the first.
There are plenty of reasons not to use try..catch blocks, but the best I've read is from here:
Exceptions are basically non-local goto statements with all the
consequences of the latter. Using exceptions for flow control
violates the principle of least astonishment, make programs hard to read
(remember that programs are written for programmers first).
Some of the usual ways around this problem are detailed here including a solution based on a new flavour of .each. This is the closest to a solution I've found so far, but I need to use .eachWithIndex() for my use case (in progress.)
Here's my own poor attempt at a short-circuiting functional solution:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
def shortestUniqueName(String nameToShorten) {
def found = ''
def final separator = '/'
def nameComponents = nameToShorten.tokenize(separator).reverse()
nameComponents.eachWithIndex { String _, int i ->
if (!found) {
def candidate = nameComponents[0..i].reverse().join(separator)
def matches = fullyQualifiedNames.findAll { String fqName ->
fqName.endsWith candidate
}
if (matches.size() == 1) {
found = candidate
}
}
}
return found
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
Please shoot me down if there is a more idiomatic way to short-circuit in Groovy that I haven't thought of. Thank you!
There's probably a cleaner looking (and easier to read) solution, but you can do this sort of thing:
String shortestUniqueName(String nameToShorten) {
// Split the name to shorten, and make a list of all sequential combinations of elements
nameToShorten.split('/').reverse().inject([]) { agg, l ->
if(agg) agg + [agg[-1] + l] else agg << [l]
}
// Starting with the smallest element
.find { elements ->
fullyQualifiedNames.findAll { name ->
name.endsWith(elements.reverse().join('/'))
}.size() == 1
}
?.reverse()
?.join('/')
?: ''
}
Wondering if I can break out of my case if the break is in an if statement, or if the break will just exit the if and not the case. I only want to fallthrough to the next case if the else is executed. Thanks
case PS_STARTED:
readyForPwrDn_b = appReadyForPwrDn_b;
if (!readyForPwrDn_b)
{
break;
}
else
{
CurrentPowerState_e = PS_COMPLETE;
}
//fallthrough
case PS_COMPLETE:
There's no such thing as breaking out of an if. break applies only to switch and to loops in all the programming languages I'm familiar with.
PHP:
break ends execution of the current for, foreach, while, do-while or switch structure.
Javascript:
The break statement terminates the current loop, switch, or label statement and transfers program control to the statement following the terminated statement.
C++:
The break statement is used with the conditional switch statement and with the do, for, and while loop statements.
However, these all apply to non-labeled break statements. In some languages you can write:
myIf:
if (!readyForPwrDn_b) {
break myIf;
} else {
CurrentPowerState_e = PS_COMPLETE;
}
This would just break out of the if.
if (condition)
{
//Do your thing
if (breakOutCondition)
return;
//Continue your code
}
This if statement would work, but there is an easy, clean way of getting out of a loop like this. You could use a goto to break this variable scope and it will make it loop a hell of alot cleaner. WARNING: goto is sometimes dreaded because it is essentially a break in disguise.
if (breakoutcondition)
{
...
goto foo;
...
}
foo:
//Continue here
You have a sequence of functions to execute. Case A: They do not depend on each other. Which of these is better?
function main() {
a();
b();
c();
}
or
function main() {
a();
}
function a() {
...
b();
}
function b() {
...
c();
}
Case B: They do depend on successful completion of the previous.
function main() {
if (a())
if (b())
c();
}
or
function main() {
if (!a()) return false;
if (!b()) return false;
c();
}
or
function main() {
a();
}
function a() {
... // maybe return false
b();
}
function b() {
... // maybe return false
c();
}
Better, of course, means more maintainable and easier to follow.
Case A: 1.
Reasoning: Since none of the functions depend on each other, calling them in order in main shows a logical sequence of events. Your alternative where they call the next one at the end of each function just looks like spaghetti code, and is hard for someone reading your program to follow.
Case B: None of the above.
function main() {
return a() && b() && c();
}
Reasoning: It seems you don't really care about the return value, you just want to break out early if one of the functions returns a certain value. You can return the "anded" result of all of these functions, and if any one of these returns false the code will break out early. So, if a returns false then b wont be executed. Placing all of them on one line is easy to read and concisely shows that they are dependent on each other.
Case A: first option
If you use the second option, you make it much more difficult to re-use a because you pull in b and c automatically.
Case b: depends - do a, b, and c return boolean values naturally, or some other value to check? I still wouldn't have a call b and b call c, because then you introduce an unnecessary dependency. If return values make sense, I lean towards option 2 - less nesting is a good thing.
First off, the best answer will depend on multiple aspects on the context the code is in - there's no one right answer other than 'it depends'.
However, taking at face value, Case A:
Option 1 shows a top level view of the algorithm.
Option 2 hides this, the calls to B & C are hidden. It could be quite a lot of work to discover the C was called. Also, it's harder to test A & B in isolation if they then call further methods. Main can always be tested if A,B and C can be mocked.
Case B:
It's common to have arguments over having 1 exit point vs multiple exit points in a method. Sometimes multiple exit points can make code simpler, which makes it more maintainable, other times it's not obvious what impact a return has, or that a return will occur, which makes it less maintainable.
Option 1 shows the algorithm explicitly, but multiple nested if's can quickly get out of hand.
In this sort of case, I'd definitely have option 2 or some clever boolean variant (yes, corey).
Option 3 looks simply obtuse to me.
Case A: first option
Case B: second option
is there a way to 'break' out of a groovy closure.
maybe something like this:
[1, 2, 3].each {
println(it)
if (it == 2)
break
}
I often forget that Groovy implements an "any" method.
[1, 2, 3].any
{
println it
return (it == 2)
}
12/05/2013 Heavily Edited.
Answering the question that was asked.
Is it possible to break out of a Closure?
You would "break" out of a closure by issuing the return keyword. However that isn't helpful in the example that is given. The reason for this is that the closure (think of it as a method) is called by the each method for every item in the collection.
If you run this example you will see it will print 1 then 3.
[1, 2, 3].each {
if (it == 2) return
println(it)
}
Why break in the context of each doesn't make sense.
To understand why you cannot break out of the each method like you could break out of a for loop you need to understand a bit of what is actually happening. Here is a gross simplification what the each method on a collection does.
myEach([0,1,3])
void myEach(List things) {
for (i in things) {
myEachMethod(i)
}
}
void myEachMethod(Object it) { // this is your Closure
if(it == 2) return
println it
}
As you can see the closure is basically a method that can be passed around. Just as in java you cannot break from within method call or closure.
What to do instead of breaking from each.
In Groovy you are supposed to express your code using high level abstractions as such primitive looping is not idiomatic. For the example that you gave I would consider making use of findAll. For example:
[1,2,3].findAll { it < 2 }.each { println it }
I hope this helps you understand what is going on.
Answering the implied question.
Can you break out of the Collection.each iterations against your supplied closure?
You cannot break out of the each method without throwing and catching an exception as John Wagenleitner has said. Although I would argue that throwing and catching an exception in the name of flow control is a code smell and a fellow programmer might slap your hands.
You can throw an exception:
try {
[1, 2, 3].each {
println(it)
if (it == 2)
throw new Exception("return from closure")
}
} catch (Exception e) { }
Use could also use "findAll" or "grep" to filter out your list and then use "each".
[1, 2, 3].findAll{ it < 3 }.each{ println it }
Take a look at Best pattern for simulating continue in groovy closure for an extensive discussion.
Try to use any instead of each
def list = [1, 2, 3, 4, 5, -1, -2]
list.any { element ->
if (element > 3)
return true // break
println element
}
The result : 1, 2, 3
Just using special Closure
// declare and implement:
def eachWithBreak = { list, Closure c ->
boolean bBreak = false
list.each() { it ->
if (bBreak) return
bBreak = c(it)
}
}
def list = [1,2,3,4,5,6]
eachWithBreak list, { it ->
if (it > 3) return true // break 'eachWithBreak'
println it
return false // next it
}
There is an other solution. Although, that groovy stuff like each/find/any is quite cool: if it doesn't fit, don't use it. You can still use the plain old
for (def element : list)
Especially, if you want to leave the method, too. Now you are free to use continue/break/return as you like. The resulting code might not be cool, but it is easy and understandable.
This is in support of John Wagenleiter's answer. Tigerizzy's answer is plain wrong. It can easily be disproved practically by executing his first code sample, or theoretically by reading Groovy documentation. A return returns a value (or null without an argument) from the current iteration, but does not stop the iteration. In a closure it behaves rather like continue.
You won't be able to use inject without understanding this.
There is no way to 'break the loop' except by throwing an exception. Using exceptions for this purpose is considered smelly. So, just as Wagenleiter suggests, the best practice is to filter out the elements you want to iterate over before launching each or one of its cousins.
With rx-java you can transform an iterable in to an observable.
Then you can replace continue with a filter and break with takeWhile
Here is an example:
import rx.Observable
Observable.from(1..100000000000000000)
.filter { it % 2 != 1}
.takeWhile { it<10 }
.forEach {println it}