switch statements in Groovy are infinitely more flexible, powerful and applicable than in Java. For this reason I've just found myself wanting to use a nested switch for the first time in Groovy.
With this:
outerSwitch:
switch( var1 ){
case 'x':
...
break
case 'y':
switch( var2 ){
case 'a':
// something
break outerSwitch
...
}
...
}
... I get a horrid message from the Groovy compiler saying "Groovy: the break statement with named label is only allowed inside loops". I don't know whether this is the same with Java.
There is an obvious silly workaround: you enclose your outer switch with a while( true ), apply the outerSwitch label to that, and put a break statement at the end of your outer switch.
Or you could do a for( int i = 0; i < 1; i++ ) ... or use a Groovy-er idiom for the same thing, I forget what all the options are... although having tried
outerSwitch:
1.times{
switch( var1 ){
...
}
... I find that the Groovy compiler gives the same nasty message. So you can't fool it with a closure, seemingly.
Is there anything in the Groovy toolkits and boxes of tricks which lets you jump out of the outer switch from the nested switch more sensibly?
The trouble being, I suppose, that when you break from a case block you don't do so with a value... if you could go break true or break 'fiddle-de-dee' there'd be obvious ways to solve this.
An obvious workaround is that you can precede your nested switch with def breakouter = false and then change that as applicable in the case block. I'd just hope that Groovy would provide something more elegant...
Not sure about the break behavior but if refactoring your switch statement is an option, perhaps the following could work:
def var1 = "y"
def var2 = "a"
switch ([var1, var2]) {
case { it.first() == "x"}:
println "var1 == 'x'"
break
case [['y', 'a']]:
println "var1 == 'y', var2 == 'a'"
break
default:
println "something else"
}
where the first case condition is a closure which will execute the case if it returns true and the second is a list of lists which will execute the case if the outer list contains the value.
This code essentially replicates the functionality in your original code snippet but with a flat switch structure. Breaking with labels, even if it worked, is in my mind not a good pattern.
Output:
~> groovy test.groovy
var1 == 'y', var2 == 'a'
Related
I just noticed that Spock does not assert the conditions if I add an if clause in the expect block as in
def myTest() {
given:
a = true
expect:
if ( a ) {
1 == 2
}
else {
1 == 1
}
}
The above test will pass since the conditions are not checked. Or the condition checking does not get forwarded pass the if statement.
The workaround to this is to add assert statements inside the if block, i.e. assert 1 == 2.
What I'm interested is, is why the functionality is like this? Is there some other way to workaround this? I'm assuming this has something to do with Groovy if statement functionality, but I don't know the language details well enough. Most probably the if statement does not return anything for the Spock's expect block to work with.
This has nothing to do with groovy. Spock's documentation clearly states that only top-level expressions are considered in then and expect as conditions. It is by design.
Search the link for top.
I wish to know how this would impact my coding when handling large volumes of data, and how I would construct my logic arguments
Two questions:
1) What are the main differences between IF-ELSE and Select CASE? Does select case operate by evaluating all cases at the same time?
If I have a situation where, by nature of its construction, need to fulfill two or more cases at the same time, for e.g.
int = 5
Select case int
Case >0
Case 5
Case <0
Where I would need to "trigger" both Cases "1" and "2" for action, do I use CASE over IF ELSE?
2) Now for the other case, if I have a variable that will trigger more one case but I would like to restrict to only one case by priority, say I would only like Case "1" for action and exclude the rest, am I right to say that IF-ELSE would triumph in this regard?
EDIT - I realized that my question was phrased poorly. I did some edits to the code
Some clarification on Select Case before actually answering your question:
as you suggested, you can combine several values in one Case switch in VBA, e.g.: Case Is>40, 20, 10, 2 To 3, for more information see documentation on MSDN
It'll execute at most one Case, it'll exit after finding a match (e.g. in the example execute Case >0 then exit without even evaluating Case 5)
It'll only evaluate your variable / expression once and use this same value for all comparisons in contrary to nested if which evaluates multiple time
if you want to execute "both" for a value you can nest if within case:
Case Is > 0
<Common code>
If i = 5 Then
<code only for case 5>
End If
Advantage of Select Case
It's more efficient when your decision is about multiple values of a single variant / expression
it also can be very useful when your expression is e.g. result of a time consuming function, in this case you really can save time compared to if
Advantage of If
Basically it's the good option in all the cases which are not described for Select Case e.g.:
you have only two options to choose from (it's the same time with both if and select, but if is easier to read)
you have multiple expressions to consider during decision and you can't easily convert them to a single value
Similarly to Select Case you can also use elseif to prepare multiple comparisons, it'll also stops at first fullfilled criteria, but here your expression will be evaluated every time until finding the match and of course you can use more complex criteria.
If-Else and Switch statement are good in different cases.
For example, If-Else has logic conditions like:
if (n < 5 && a > 5) { } // && is a logical AND
and nested constructions like
if (n < 5) {
if (n < 0)
{
}
else
{
}
} else { }
You cannot do this in switch statement.
However, switch is better, more elegant and faster in some situations:
switch (a)
{
case 1:
case 2:
case 3:
// ...
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 10:
break;
default:
break;
}
would look very bad in if-else format:
if (a == 1 || a == 2 || a == 3)
{
}
else
if (a == 4)
{
}
else
// ...
I'm not sure about your case but in most languages switch statement is more performant.
Simply said, use switch statement every time it is possible and there are more than two cases. If there are only two cases or it is impossible to use switch - use if.
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
I've been wondering myself multiple times if, and if not, why not, there is an idiom/shortcut for the following pseudocode:
if object.value == some_value then object.value = some_other_value
For example, in JavaScript I sometimes write:
if (document.getElementById("toggledDiv").style.display == "block") {
document.getElementById("toggledDiv").style.display = "none";
}
This seems to be rather tedious. Is there a name for this idiom, and is there a more concise syntax for this in common programming languages?
Thank you!
Edit: To be more precise, I don't care about the braces, but about that you have to reference the attribute at least to times. I'd like to have something like that (pseudocode):
test ( object.value ):
if (it > 0) it = 0;
else it -= 1;
e. g.:
test (document.getElementById("toggledDiv").style.display):
if (it == "block") it = "none";
where it is a keyword that references the tested property. I'm just wondering no programming language seems to have implemented that.
Upate:
Okay, in the meantime I have found something which is a little bit short, but only works in JavaScript:
(function(s){
if(s.display=='block')
s.display="none";
else
s.display='block';
})(document.getElementById("toggledDiv").style)
Well, in Haskell, and other FP languages, conditionals, like ternary operators, are first-class expressions, so you can float the assignment out,
a = if x == y then x else z
Making the code a lot cleaner.
I don't know of any languages that support it out of the box, but there are a number that support defining new operators. In theory, you could write something like the following (in psuedo-code)
operator <T> T toggle(T value, T[] values) {
for(int i=0; i<values.size(); i++) {
if(value == values[i]) {
if(values.size() > (i+1)) {
return values[i+1]
} else {
return values[0]
}
}
}
error "value $value not found in value list $values"
}
Assuming my psuedo-code is correct, this would allow you to do the following:
v = true;
v = v toggle [true, false] ; // v == false
v = v toggle [true, false] ; // v == true (loops to beginning of list
v = v toggle [false, true, true] ; // v == true, since true is both the 2nd and 3rd elements of the list
You could also two versions:
One that, if the values isn't in the list, returns the original value
One that, if the values isn't in the list, throws an error (what my version did)
The former would be less of a toggle and more of... what you asked for, I guess. I was basing the code off the toggle use case from the previous note about css/block/none, where toggle is the more common behavior.
Assuming the language supports it, you could write a toggle= operator too:
v toggle= ['none', 'block']
In JavaScript you can do:
var d = document.getElementById("toggledDiv");
if (d.style.display == "block") d.style.display = "none";
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}