views:

194

answers:

6

If a BOOL has a nice short name, it's easy enough to write:

myBOOL = !myBOOL;

But what if the BOOL has a long name?

objectWithLongishName.memberWithLongishName.submember.myBOOL = !(objectWithLongishName.memberWithLongishName.submember.myBOOL);  

. . . does not look so pretty.

I'm wondering if there is an easy way to toggle the BOOL without entering its name twice?

+8  A: 

No there isn't an obvious way in (Objective-)C to do what you describe (without using a preprocessor macro), but see Seva's answer for a possible (though potentially brittle) solution. More importantly, something like objectWithLongishName.memberWithLongishName.submember.myBOOL indicates a Law of Demeter violation; you should be providing submember directly to any code unit that needs to access submember.myBOOL.

Barry Wark
Why is aBool ^= YES unfeasible?
Kalle
@Kalle, good point. I think @Seva Alekseyev makes the point pretty clearly. Using `^=` is potentially brittle, but will work in many situations.
Barry Wark
+4  A: 

Write a method for the submember class that toggles it for you?

- (void) toggleMyBOOL {
  self.myBool = !self.myBool;
}

Then you can do:

[objectWithLongishName.memberWithLongishName.submember toggleMyBOOL];
Dave DeLong
+5  A: 
#define NOT(b) (b) = !(b)

NOT(MyBooleanVariableWithAFreakishlyLongName);

Or, if it's Objective C++:

void NOT(BOOL &b)
{
    b = !b;
}
Seva Alekseyev
I would've named the macro TOGGLE, but whatever does it for ya...
FrustratedWithFormsDesigner
That was my first draft :)
Seva Alekseyev
+2  A: 

Here's another:

MyBooleanYaddaYadda ^= YES;

This is kinda brittle - it will break on legacy C code that implies that any nonzero integer evaluates to true. But then again, so will Apple framework code - I encountered cases in Cocoa where a nonzero, non-one int, when passed as a BOOL, would not cause the same effect as passing a YES.

However, it does not rely on the bit pattern of YES - only on NO being 0. Which is pretty much a given, giving the way C interprets integers as logical values. Also, it does not assume the actual datatype of BOOL (which on Cocoa is signed char, by the way).

Seva Alekseyev
It kind of fails from a code clarity point. At a casual glance, it looks like an assignment to YES. Use it a lot, and the idiom will likely stand out, but hit it fresh, it'll probably cause a bit of head scratching.
Will Hartung
IMO the brevity and lack of required associated infrastructure (i.e. macro definitions) outweigh this disadvantage. That's why I accepted this answer. To each his own, though.
William Jockusch
+1  A: 

Use XOR. In C, this is ^.

BOOL x = YES;
x ^= YES; // it's now NO
x ^= YES; // it's now YES
x ^= YES; // it's now NO
x ^= YES; // it's now YES
x ^= YES; // it's now NO
x ^= YES; // it's now YES
...

Edit: someone posted this already, apparently. I guess I should say I've never actually used this in code. :-)

Kalle
Note that that's a bitwise XOR, which means that if `x` is, for some reason, set to any value other than 1 or 0, it will always remain true, since you're only flipping the lowest bit. Using `~NO` will replace that problem with another: You'll be flipping *all* the bits, with the same result: `x` simply alternates between two true values.
Peter Hosey
And *that's* why I posted it as a comment and said "…but I wouldn't". ;) It sure is "neat" though.
Wevah
If you manage to get a BOOL to equal a value other than 1 or 0 then yes, you'll have problems. But won't you, regardless?
Kalle
A: 

You have a lovely set of answers focused on flipping a YES to a NO or vice-versa, but no answers that touched on what would appear to be an architectural issue in the code.

Well, some answers. I'm blind.

Namely, you have this:

objectWithLongishName.memberWithLongishName.submember.myBOOL =
    !(objectWithLongishName.memberWithLongishName.submember.myBOOL);  

That smells like a potential encapsulation violation. In particular (and assuming this is a model layer), it means that the connectivity of the sub-graph of objects is being overtly exposed -- flattened into, effectively -- the entry point of that path; whatever objectWithLongishName is must now have rather intimate knowledge of the innards of the objects along the rest of the path.

Typically, you don't reach deeply into the model layer along key paths to edit state outside of the Cocoa Bindings layer (and even that is a bit fragile).

Sometimes such long-ish paths do make sense. In such a case, I would leave the über-verbose form you have above as a visual indication that encapsulation is being purposefully shred.

bbum
@Barry Wark mentioned this (The violation of the Law of Demeter)
Dave DeLong
Actuall, the *first* (or one of the first) answer (Barry Wark's answer) mentioned that.
FrustratedWithFormsDesigner