Code idiom: using logical ^ to change your mind
# 2003-03-26 16:22:41 -0500 | Java | 8 CommentsThis idiom is a cool little trick, but I’ve seen coders scratching their head trying to work out what it does; so a detailed explanation is in order.
The ^ bitwise exclusive-or operator (or “XOR”)
is standard computer science fare. An XOR is often used to
flip bits in a byte/word. In Java, the ^ bitwise operator
works on all the integer types
(int,
byte,
short,
char,
and long)
and performs an XOR between each corresponding bit in the arguments.
But, if the operands to ^ are both boolean,
then a logical exclusive-or (LXOR) is performed (as opposed to
a bitwise XOR). The result of LXOR is “true if the
operands are different; otherwise false if they are the same”.
The truth table for x ^ y looks like this:
x | y |
false | true |
|---|---|---|---|
false | false | true | |
true | true | false | |
The idiom: using ^ to change your mind
Can you work out what the following code does?
public static boolean isTuesday(boolean invert) {
GregorianCalendar now = new GregorianCalendar();
boolean isTue = now.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY;
return isTue ^ invert;
}
System.out.println(”is Tuesday? ” + isTuesday(false));
System.out.println(”is not Tuesday? ” + isTuesday(true));
The trick utilises this:
(x ^ false)is always justx(x ^ true)negatesx, it is!x
So, if you have some code that conditionally needs to do the opposite of what it normally would do (that is, it needs to “change its mind”), just pass an “invert” argument, and LXOR with that argument when making decisions. (You could call this argument “invert”, “reverse”, “negate”, etc. depending on the particular semantics.)
Applied example: AbstractConditionalTag
Here is the code for a useful AbstractConditionalTag JSP Taglib
and an example “is Tuesday” tag.
public abstract class AbstractConditionalTag extends TagSupport {
private boolean invertTest = false;
public void setInvert(String invert) {
invertTest = "true".equalsIgnoreCase(invert);
}
public int doStartTag() throws JspTagException {
try {
boolean result = evaluateCondition() ^ invertTest;
return result ? EVAL_BODY_INCLUDE : SKIP_BODY;
}
catch (RuntimeException e) {
Logger.log(this, e);
return SKIP_BODY;
}
}
protected abstract boolean evaluateCondition()
throws JspTagException;
}
public class IsTuesdayTag extends AbstractConditionalTag {
public static boolean evaluateCondition() {
GregorianCalendar now = new GregorianCalendar();
return now.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY;
}
}
And you would use it in a JSP page like this:
<tag:isTuesday> It's Tuesday; rubbish day! </tag:isTuesday> <tag:isTuesday invert="true"> Don't put the rubbish out today. </tag:isTuesday>
I’ve recently saw a pair of conditional tags <IsNull> and <IsNotNull> implemented with an abstract base class that has the method:
protected abstract boolean isNullAGoodThing()
Each tag is implemented with a very short subclass, one implementing this method as "return true", and the other "return false". I’ll have a look at that code again and see if I could replace it with a single class using ‘^’.
Alan
PS: Your smileys are just too cute :D
You made me :? quite hard with this one, but I am now :-D
Matt wrote:
This idiom is a cool little trick, but I've seen coders scratching their head trying to work out what it does; so a detailed explanation is in order.
I think the fact that coders are scratching their heads makes this more of a "trick" and less of an "idiom". That you leave coders puzzled is enough of a reason not to use it, since it doesn’t really buy you much, and the readability of the code is reduced.
For me, I’d prefer to see it spelt out:
boolean result = evaluateCondition();
if (invert) {
result = !result;
}
return result;
Sure it’s a bit more typing, but it doesn’t require the audience to have a knowledge of an arguably obscure language feature. When running the latter chunk thru my wetware language parser, it reads quickly and elegantly.
While I agree with you Brendan, I would redo your example as:
final boolean result = evaluateCondition();
return (invert) ? !result : result;
I find this approach improves code coverage and is easier to read. >:)
You could also do:
return result == ! invert;
Or just:
return result != invert;
too clever by half.
..at least.
Just plain evil.