Is "&&" equal to ","?

Not that I expect what I'm about to suggest to be implemented due to its source-breaking nature, and probably a million other things I haven't thought of, but I almost wonder if it would be better to have four separate operators: &&, ,, &&,, and ,&&.

if cond1 && cond2 {}
if cond1 &&, let x2 = y2 {}  # New
if let x1 = y1 ,&& cond2 {}  # New
if let x1 = y1, let x2 = y2 {}

The two new operators would add clarity to the situation -- on the comma side of the operator we are always assigning a new non-nil variable, and on the ampersand side we are always checking a boolean value.

Honestly it’s not that it becomes an issue, just that it’s usually nicer to be rid of the outermost parenthesis if each part between && is complex like (a || b) && (c || d)

There’s also this interesting bit that if conditions are indented in the same level as the then block, so if you declare multiple variables in the condition expression, it ends up flowing pretty nicely (but that’s for multiple let that forces , anyway).

I think the design came up during the pitch to have let be separated by &&

if let a = a && let b = b {}

Something like that.

The issue with introducing special purpose symbols is it breaks orthogonality. And history has taught us this is often a very bad thing.

For those not familiar with orthogonality, let me give a simplified explanation (taken from IBM vs DEC but using made up operations for simplicity)

IBM built a processor with instructions to move data between registers (say, A, B) and memory (say &m).

They had instructions like this:

MVmA &m // move memory value to A register
MVmB &m // move memory value to B register
MVA &m // move A register value to memory
MVB &m // move B register value to memory
MVAB // move A register value to B register
MVBA // move B register value to A register

This was non-orthogonal, multiple instructions each with their own syntax.

DEC took a different approach, using just one instruction with one syntax

MV x,y

But you could use this instruction in any way that made sense.

MV A,B  // move A register value to B register
MV B,A  // move B register value to A register
MV A,&m  // move A register value to memory

This is the orthogonal approach and with it you could do more with less, for example:

MV &m1, &m2 // Move value from memory location 1 to memory location 2

Despite having 6 different MV operations, the IBM way didn't have a way of achieving this memory to memory move. Instead, you had to move from memory to register, and then from register to different memory.

This is the power of orthogonality.

Now consider the subject of this question.

We have:

&& // combine values with boolean logic

And in normal use we have

, // separate values (eg: parameters, array items)

Yet in this question we have

var a: Bool
var b: Bool

if a && b {
    //todo
}

if a, b {
    //todo
}

That is, a combine operator and a separator operator being functionally equivalent. It's really quite horrible, no?

I appreciate the difficulty language designers face. Take a quick scan across your keyboard and note how virtually all the symbols are already assigned some semantic meaning. What's a designer to do?

Perhaps the back-tick is still available and could be given the semantic meaning - true if enclosed assignment succeeds, to give:

if (a && `let b = optionalB`) {
    // to do
}

Or then again, perhaps not!

But all I was trying to say was that between the two, && retains orthogonality better and so for me is the better choice when the features of ',' (eg: assignment) are not being used.

How is it redundant? It’s needed to disambiguate between the logical and the bitwise AND operators, non?

1 Like

Actually, I think it's not strictly necessary, because 0 (and other numbers) isn't considered to be a Bool.

extension Bool {
	static func &(lhs: Bool, rhs: Bool) -> Bool {
		return lhs && rhs
	}
}

print(true & false) // compiles just fine

Unlike in languages of antiquity, Swift's Bool is not a BinaryInteger.

Bool only has &&, and BinaryInteger only has &. (The same goes for || and |, but there's no "or" punctuation to match the "and"-comma.)

If Bool only had &, then some people would be confused and unhappy when the expression on the right wasn't evaluated when the expression on the left wasn't true. But they'd probably generally be the ones who argued against "C-style for loops" and ++ being removed.

I have no hope that the second & will ever be removed at this point, but I argued against it in 2014, and still hate it, so any chance I get to use something else built-in that avoids it, I do that! :smiley_cat:

1 Like

Given that operators can be overloaded (for new types or combinations of types), it would be shortsighted to also overload the meaning of the operator. There is nothing stopping you from implementing & for Bool that does a bitwise and, returning whether or not the result is a boolean true or false.

1 Like

This thread has gone on for so long, I simply cannot resist anymore. So while I know this won’t actually help anyone...

&& is a stuttering Roman; use .

10 Likes

There is a half-finished presentation in my drafts folder called “Boolean Algebra for Swift Developers.” I began writing it after experience taught me an obvious but important lesson: Swift developers are better at Swift than they are at Boolean algebra.

Part of the genius of the comma syntax is commas have higher precedence than any operator. Any statement bracketed by commas can always be reasoned about in isolation from the rest of the condition. Developers know to read a condition comma-by-comma, bailing out as soon as one statement is false. This is true even of developers who otherwise fumble with pure logic. I think it is a best practice to rephrase conditions into named values separated by commas, partly because it is idiomatic and easy to read, but mostly for all the devs out there who don’t know their ps and qs.

10 Likes
Terms of Service

Privacy Policy

Cookie Policy