Is it possible to create `and` and `or` extension for `Bool` type?

One thing I don't like from Swift syntax is its cryptic logical syntax e.g. && for and, || for or, ! for not. I knew it's impossible to make a string as an operator in Swift. I'd like to make an extension for each of them to Bool type. So, I could do this:

true.and.false instead of true && false
true.or.false instead of true || false
not.true instead of !true

But first of all, is it possible to make such extension in the first place?

If it is then I don't know how to make it works on both side values without making it as function. So far, what I could do is this:

true.and(false) instead of true && false
true.or(false) instead of true || false
not(true) instead of !true

But it looks ugly.

Any hints? Or is it also impossible to do? Thank you.

~Bee

That shouldn't be hard - but I guess you actually want

let myBool: Bool
...
not.myBool

... and this isn't possible.
At least I can't think of any way how to do this in Swift: Making it valid syntax should work with the dynamic-features, but how would you access the value of myBool?

1 Like

I hate to be "that guy", but this is one of those places where you kind of just have to get used to it. These operators originate from C, and are ubiquitous in C-inspired languages (like C++, C#, Java, ObjC, Swift, Ruby, PHP and Perl).

Even though I prefer the Python "spelt out" syntax (a and b, not a, etc.), that ship has sailed for Swift, unfortunately (for me). Memorizing them will be helpful to you, not only for Swift, but also for reading any other C-inspired language code.

Also, this hand-rolled operator system will have the same "I don't like this cryptic logical syntax" reaction from everyone else who isn't the author of it (you).

12 Likes

“Spelled out” syntax is actually in the commonly rejected changes list: swift-evolution/commonly_proposed.md at master · apple/swift-evolution · GitHub

3 Likes

Check this out!

precedencegroup BoolOperator {
    associativity: left
}
infix operator ..: BoolOperator


struct BoolOperator {
    let op: (Bool, Bool) -> Bool
}
struct PartiallyAppliedBoolOperator {
    let op: (Bool) -> Bool
}
func ..(lhs: Bool, rhs: BoolOperator) -> PartiallyAppliedBoolOperator {
    return PartiallyAppliedBoolOperator(op: { rhs.op(lhs, $0) })
}
func ..(lhs: PartiallyAppliedBoolOperator, rhs: Bool) -> Bool {
    return lhs.op(rhs)
}


// You cannot write `BoolOperator(op: &&)` because && takes an autoclosure
let and = BoolOperator(op: { $0 && $1 })
let or  = BoolOperator(op: { $0 || $1 })

print(true..and..true) // true
print(true..and..false) // false
print(true..or..false) // true

let x = true
let y = false
print(x..and..y) // false
print(y..or..x..or..x..and..y) // false
print(x..and..(x..or..y)) // true
5 Likes

Clever! Though you probably should use an autoclosure so evaluation of the right hand side is short-circuited when the left evaluates to true.

3 Likes

Good idea. I'll leave that as an exercise for the reader :)

note, that in C/C++ you can actually write "and" / "or" instead of && / || since very long time ago.

with the help of an extension on Bool you can write today: "x.not" if you prefer so. would be somewhat equivalent to a phrase: "i am glad to see you. not". and of course you can write and(a, b) / or(a, b) but that's probably not what you want.

personally i do not dislike && / || much. although i'd prefer them to be spelled & / I (the same way as they are used for bitwise operators). in C it was important to have two different sets of symbols to distinguish bool vs bitwise ops, in swift not so much. in swift whether the operator short-circuits or not is not a feature of the operator symbol itself, it is a feature of the corresponding function, so you can have, say, & that short-circuits for Bools and that doesn't short-circuit for Ints.

the ! symbol for bool negation is not my favourite as it collides with unsafe optional unwrapping. personally i would use ! just for optionals. consider !x! - way too horrible. that one i'd change to anything else, any day. ~~ would be a consistent with bitwise ~ and follow the same pattern.

OTOH, if you are a fan of reusing operator symbols you can write today (with the help of an extension) confusing your colleagues:

a + b instead of ||
a * b instead of &&
-a instead of !

or follow the established tradition of doubling symbols for bools:
a ++ b a**b --a

on a different note, shall false / true be spelled .false / .true? that would make it more logical. although we'd probably hate it :-)

this one actually compiles:

infix operator
infix operator
prefix operator ¬

func ⋎(a: Bool, b: @autoclosure () -> Bool) -> Bool {
return a || b()
}

func ⋏(a: Bool, b: @autoclosure () -> Bool) -> Bool {
return a && b()
}

prefix func ¬(a: Bool) -> Bool {
return !a
}

3 Likes

Thank you for all responses. I do appreciate them all.

I don't want to change Swift because I know I'm just a user. I know I have to accept it as is. I only want to make a workaround on something that I personally don't prefer. The cryptic logical syntax is one of them. However, if it's not possible then fine.

I can accept operator symbols for bitwise operations. We rarely use it anyway. But I don't like it for logical operations. It looks weird to my eyes and hurts the code readability. I don't know, perhaps because I used to be a Python and Pascal programmers before I learn Swift. So, I also don't prefer any offered solutions that still use operator symbols. Sorry.

If it's indeed impossible to do then I think I have to adjust myself to accept it. I'm starting to love Swift but this little thing still annoys me.

1 Like

This is mostly a matter of familiarity. Usually, whether or not something is natural, logical or easy, boils down to whether it is familiar.

Neither of them is objectively better, it's just a matter of convention.
And you'll soon find that it reads naturally and simply.
(And in fact, to the vast majority of programmers in the world, the && is the most familiar option.)

6 Likes

not that bad idea. as a trial i introduced ~ for not and <> for != in my code base.
now i can search for ! and they only relate to optionals.

func toggleCollapsed(animated: Bool = true) {
    setCollapsed(~isCollapsed, animated: animated)
}

var isVisible = false {
    didSet {
        if isVisible <> oldValue { update() }
    }
}

very true!

of course there are cases when something is ugly beyond repair (like obj-c method calling syntax even if you dealt with it 15+ years) but && is not one of those.

1 Like

I like that you're going to town but I hope you're not sharing this code base with anybody because it would be confusing as heck to work with this as a Swift developer.

Re: the ! for optionals, you should only very rarely be using it. I'm almost positive that if it weren't for Objective-C interop, the ! for optionals might not even have existed in the first place.

SwiftLint is smart enough to distinguish negation from force unwrapping, so this isn't really necessary

I disagree with this. Something familiar is not always correct, or natural, or logical. Mathematically speaking, x = x + 1 is not correct although it's very familiar to almost all programmers. And I think there are a lot more people understand math than programming. Perhaps that's the reason some programming language use := for assignment operator e.g. Pascal.

If we really want to be strict with math, Swift should use for logical and operator, for logical or operator, and ¬ for logical not operator, instead of &&, ||, and ! respectively. The problem is, those mathematically correct symbols aren't accessible on common keyboard so the better alternative is spelt out string operators. But Swift doesn't allow string operators so it uses neither of them, which is very unfortunate.

For what it's worth, and like other have pointed out, Swift is not even close to being the only language that uses this syntax. Languages like PHP, Javascript, Objective-C, Kotlin, Java and many more use the same symbols.

So even if they're all mathematically wrong, they are what quite possibly a majority of the programming community is used to.

Also, I'm quite happy that it's not possible to define and, or etc. as keywords for equality. We already have established comparison operator and I don't think we need more of operators that do the same thing.

*APL intensifies*

life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}
3 Likes

I don't want to change Swift. I didn't even propose any changes to Swift syntax. I was just asking if is it possible to do what I want to do. So nobody has to do the same thing as I would do and could keep using the standard Swift syntax. You do not need to worry about anything.

If that so then why Swift don't use , , and ¬ symbols, or since the first time?

This is because:

Swift is designed to feel like a member of the C family of languages

(Quoted from https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md)

:slight_smile:

the <> symbol was used in many programming languages so it shall not be too alien. ~ symbol is used in C/swift for a similar concept (bitwise negation).

dunno... now that i made this conversion of my code base i found that there are 200 ~ symbols (for not) 300 <> symbols (for inequality) and 1000 ! symbols - the latter are mostly in connection with optionals / type casts.