1
if ([_managedObjectContext hasChanges] & ![_managedObjectContext save:&error] ) {
}

I always use && in conditional sentences, today suddenly see there is only & in the above sentence, what is the difference between them in this sentence?

Update: the code above is wrong, it just a typo, sorry, it should use &&, not &, and look like this:

if ([_managedObjectContext hasChanges] && ![_managedObjectContext save:&error] ) {
}
zgjie
  • 2,099
  • 2
  • 21
  • 32
  • It's a perfectly valid statement from the compiler's view but is definitely a typo in this context. – CrimsonChris Jun 25 '14 at 15:43
  • @Sulthan You would expect the save method to be run even if there _hasn't_ been changes? Doesn't make much sense to me. – CrimsonChris Jun 25 '14 at 15:46
  • 2
    @Sulthan, I can't understand what reasoning you would give for calling CrimsonChris wrong. His comment is absolutely correct: The statement is valid, but most likely not doing what the programmer intended. Your other comment is nonsense. Completely the wrong way round. – gnasher729 Jun 25 '14 at 15:47
  • Oh I see your point now. `hasChanges` evaluating to true with `&&` would actually execute `save:`. Mea culpa. – Sulthan Jun 25 '14 at 15:53
  • 1
    hasChanges evaluating to true _will_ and _should_ call save: whether you use && or &. hasChanges evaluating to false _should not_ call save:. With && it doesn't call save: With & it _will_ call save: which is wrong. – gnasher729 Jun 25 '14 at 15:59
  • @zgjie Please destroy this code. It's ambiguous and needs to die. : ) – CrimsonChris Jun 25 '14 at 16:04

2 Answers2

4

& is a bitwise AND operator. Unlike logical &&, it

  • Produces values based on all bits of the two operands, and
  • Does not short-circuit the evaluation.

In this particular case the fact that the operator operates on all bits is not relevant, because the second operand has ! in front of it. This is a logical NOT, so its result is going to be either 1 or 0.

However, the absence of short-circuiting is relevant: there would be a call to the [_managedObjectContext save:&error] method, even if [_managedObjectContext hasChanges] returns zero.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thanks for your explanation. Based on your answer, I'd agree that this may be intended behavior, but I'd still classify it as problematic code. – Palpatim Jun 25 '14 at 15:45
  • 2
    @Palpatim I would definitely agree that this code is highly suspicious, precisely because of lack of short-circuiting: it calls `save:` even in cases when the context has no changes, which is in all probability a redundant operation. – Sergey Kalinichenko Jun 25 '14 at 15:47
1

It has been explained what is the difference between & and &&, but the code is actually a bug:

save: will be called, whether hasChanges is true or not. That is very strange - when there are no changes, there is no need to call save:. If there is actually code between the curly brackets, that code would be executed if there are changes and save: fails. If there are no changes, and save: fails for any reason, then the failure would not be detected. If there is no code between the curly braces, there is no need to call hasChanges at all if save: is going to be called anyway.

Since it is completely weird what the code does, and there are no comments why the code is weird, it is a bug.

In general, using & for logic is highly suspicious. & should be used for bitwise and, like

if ((value & mask) != 0) ...

If you really want a "logical and" and evaluate both halves (for example because they have side effects), you would write

BOOL hasChanges = [_managedObjectContext hasChanges];
BOOL saveFailed = ! [_managedObjectContext save:&error];

if (hasChanges && saveFailed) ...
gnasher729
  • 51,477
  • 5
  • 75
  • 98