Adding toggle to Bool

I agree, we are derailing the thread. I only mentioned it because people were talking about solutions for '... == false'. I'll create a new topic and we'll see whether there is any support for this.

Let's bring the discussion back to adding a toggle() function to Bool. I totally support this and 'toggle' as name seems fine to me.

1 Like

I'm +1 for such an extension, though I'd prefer to name it invert(), as toggle() seems to be too much skeuomorphic. :upside_down_face:

4 Likes

invert is misunderstandable with number inversion.

3 Likes

I think toggle is nice.

(this deviates a bit from this thread's intent, but might be useful.

And for some the "!" seems to be ! isVeryReadable

Then I thought maybe I could do something like this:
define a not operator as prefix "not"

static prefix func not(b: Bool) -> Bool { return !b} 

nested inside a Bool extension, but Swift doesn't allow words as operators
Why not?
If that was possible one could define a prefix operator "not" for example, used like so:
if not isHere { ...}

You could use a public function:
public func not(_ b: Bool) -> Bool
{
return !b
}
(assuming here btw that the swift optimizer makes this inline as just b = !b)
then it looks much clearer like so:
var isHere = not(isAway)

if not(isHere)
{
    print("He's not here.")
}

Recommended:
I always use the "is" prefix for booleans like
isAway, isIndexLoaded, isAscending etc
I never, never, never use isNotHere, isNotThinking,isNotPlaying,
for obvious reasons.

One might ask why not have keywords for boolean operators?
like "not" "and" "or" "xor"

then it's a lot more readable like so:

if not (isLoading or isWaitingForConnection) and isUserConnected {...}

why not?

TedvG.

1 Like

See the list of commonly rejected proposals.

1 Like

Ok, forgot about that, it's been some time.
So this operator restriction: (re)defining or language keyword implementing:
using words as operators,
is here, just because the current compiler
isn't smart enough (yet) to handle this.
right?
(it's a pity AND OR and NOT have been available in older languages
like Pascal and Cobol
Fortran uses .and. .or. , .not. (between dots)

I was almost starting a new topic asking to implement operator definition
with words, never mind... :o|
TedvG

If you want to implement and/or/not as functions, don't forget to use @autoclosure to get the same short-circuit behavior the operators have:

import Foundation

func not(_ b: Bool) -> Bool {

return !b

}

extension Bool {

func and(_ b: @autoclosure ()->Bool) -> Bool {

if !self {

return false

} else {

return self && b()

}

}

func or(_ b: @autoclosure ()->Bool) -> Bool {

if self {

return true

} else {

return self || b()

}

}

}

let scrunchy = true

let longhaired = false

if not(longhaired).or(not(scrunchy)) { print("can't") }

if longhaired.and(scrunchy) { print("can") }

if scrunchy.or(longhaired) { print("or.") } // longhaired not evaluated

if longhaired.and(scrunchy) { print("and.")} // scrunchy not evaluated

Personally I'd prefer not to implement those boolean operators as functions
but as real -or custom defined- operators, but alas, that's not possible...

If using @autoclosure for the sake of performance improvement,
You can just as well omit this for these trivial functions.
I think the performance gain would be neglectable
because I am pretty sure the compiler will replace the complete not(...) function
with an in-line "b = !b", right?

TedvG

autoclosure isn't for performance here. "not" doesn't need it.

a && b where a is false doesn't evaluate b.

a || b where a is true doesn't evaluate b.

For ordinary methods, the arguments are evaluated before calling the method; @autuclosure lets us defer evaluating arguments.

Question: Does a user-implemented && or || operator evaluate both arguments before calling the user's function?

func and(_ b: @autoclosure ()->Bool) -> Bool {

    if !self { 

        return false 

    } else {

        return b() 

// doesn't need self && b()

    }

}

C. Keith Ray

https://leanpub.com/wepntk <- buy my book?

http://agilesolutionspace.blogspot.com/

twitter: @ckeithray

http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

1 Like

I think these are interesting topics, but quite far off-topic. I would like to keep the discussion reasonably focused here.


C_Keith_Ray
C. Keith Ray

    January 22

autoclosure isn’t for performance here. “not” doesn’t need it.

a && b where a is false doesn’t evaluate b.

a || b where a is true doesn’t evaluate b.

For ordinary methods, the arguments are evaluated before calling the method; @autuclosure lets us defer evaluating arguments.

Question: Does a user-implemented && or || operator evaluate both arguments before calling the user’s function?

func and(_ b: @autoclosure ()->Bool) -> Bool {

>     if !self { return false } else {
> return b()

// doesn’t need self && b()

>     }
> }
1 Like

OK, you're right.
I think .toggle() is nice, but one of the virtues of Swift is that one can use extensions, which I'd guess most of us have done already for .toggle() and a myriad of other "language improvements" ?
Regards

I think there may be a larger issue at play here, which manifests itself when toggling Booleans: the inability to concisely refer to the LHS of an assignment on the RHS. If Swift had a keyword like “lhs” or “itself” or something of that nature, then you could write some.reallyLong.expression = !itself. This has the advantage of working in other cases besides toggling a Boolean, such as someNum = itself * itself

10 Likes

highkey i really like this idea

It's not a matter of "the current compiler isn’t smart enough (yet) to handle this." You're criticizing before thinking about it.

The compiler could be made to allow operator and identifier characters to overlap. The compiler isn't the isuee. The issue is that the compiler isn't the only program that has to parse Swift code. Text editors, linters, websites' code highlighting, etc. all would need to be built with the ability to parse all dependencies to learn about what operators are available, so as to determine which identifiers are operators, and which are just identifiers. That will never happen.

On the other hand, you could take the Python approach of hard coding a fixed set of reserved words. That makes the tooling support easy, but isn't flexible.

Can we please keep the conversation on topic? We can branch out for other discussions, as they're useful in their own right. Or maybe a moderator can close the topic, as the replies don't seem to focus on the proposal.

4 Likes

I'lll spawn a new "compiler vs. user" topic.
Concerning this topic:
imho these(like toggle()) are just syntactic sugar that can be
implemented using class/struct extension if a user desires it.
but that's me.

After further thought I think there is one area that hasn't been mentioned yet where toggle and toggled would be incredibly useful: optional booleans. Currently, if x is a Bool?, then !x is not allowed. However, x?. toggle[d]() would be allowed. This would allow the following:

var x: Bool? = true
x?.toggle()
if x?.toggled() ?? false {}

Currently you must do the following to allow use of ! with optionals:

var x: Bool? = true
if let y = x { x = !y }
// the next two lines are valid ways to return an inverted copy
if x.map({ !$0 }) ?? false {}
if let y = x, !y {} // Should we really need a whole new variable here?

The first code block is much nicer than the second.

2 Likes

Though you can't use the ! operator on Bool? variables, you can still test for equality using ==:

var x: Bool? = true
if x == false { /* code not run if x is `true` or `nil` */ }

Your point stands for mutating Bool? variables, as x?.toggle() is clearer than x = x.map(!).

1 Like

Have you thought about using a non-mutating toggled().
Also, have you thought about returning the toggled() value for more one-lined mutations with the @discardableResult property?

This ship has already sailed: Accepted: SE-199 – Add `toggle` to `Bool`.

1 Like