SE-0199: Adding toggle method to Bool

-1, agree with what @Erica_Sadun said.

David Hart mention a good argument against the name invert in the pitch thread: it is misunderstandable with number inversion. Toggle doesn't have that problem.

1 Like

With a lot of developers that come from countries where English is not the first language. The verb that is chosen is very important as each word has a meaning which could be interchangable for English speakers, but changes meaning for others.

switch - this would not provide much context and also confuse with the already present switch statement
toggle - this would mean more like an on/off than true/false boolean.
invert - this would mean to invert the value and in the case of boolean, most appropriate
negate - this would generally mean to make negative, also indicating that there would be another method to make it positive.

so from the options above about choosing a verb, my vote is with invert

When implemented, hope that it is as fast or better than the ! operator, and if this 'invert' is implemented, then would the ! be open to be used for operator overloading?

I’m mildly against this proposal, echoing the sentiments of others:

  • I don’t think it’s useful enough in all or most projects to end up in the standard library
  • I don’t really agree on the name (it’s not universally applicable, just as YES and NO in ObjC often look silly)

On the plus side, someone made a point about optional chaining. This is very often an advantage of having methods like this (regardless of the underlying type) and I wonder whether it implies there is a larger point to be made about handling optionals differently in general somehow.

If the proposal was accepted for the above reason, my impression is that it’d be more Swift-like to have a non-mutating “toggled” function like this:

var myBool: Bool?
myBool = myBool?.toggled()

-1 from me, agreeing with @Erican_Sadun.

Additionally, if you have an instance where you want to toggle a property on another object, that object should give you a more descriptive method to call instead, e.g. rather than...

task.completed.toggle()

...consider...

task.complete()

Thanks to Chris Eidof for this proposal.

I'm +1 because this toggle method won't bother me when I don't use it, and will come in handy when appropriate. I don't care about its name.

To go further, I wish I would read more proposals that add convenience methods in the standard lib. Being fluent (not short or terse) is good for a language, its ecosystem, its culture, and vocabulary.

2 Likes

+1.

This apprehension to adding things to the standard library is what brought us to the current (incredibly lacking) state of the standard library and Foundation).

1 Like

+1

The current manual method requires writing the reference to the object on both sides. This is wide open to misspelling mistakes, and the proposal closes the hole. (If the misspelling is total, then we get a compile error. But imagine if the misspelling pointed to another object instead. That would be very bad on the read side, and really very bad on the write side.)

Also, I've been playing with a packed-Bool collection type. I was thinking of including set-all, clear-all, and flip-all methods like Java's BitSet has. The set- and clear-all methods would have single-element equivalents (just assign from true or false, respectively). Now I don't have to worry about adding my own extension for the individual flipping case.

+1. I think it's a clever addition to Swift that embraces its unique value-based mutation features.

3 Likes

+1.
I refuse to add that extension to my projects to avoid creating a dependency on something that's not a part of the language. Having it built in will encourage me and others to use it.

The name toggle() doesn't fits though. There might not be a switch behind that boolean. reverse, negate or something more generic makes more sense to me.

+1 Sound an usefull one when available trivial additive API
Could help to make source code and its logic more readable.

What does s.c here stand for? Thanks

Sorry, I edited my answer to fully write Source Code

After reading through more comments and responses from @Ben_Cohen and @Chris_Eidhof, I see there are more benefits to this than the proposal brings to light. I’d like to see the proposal updated with more of these benefits and then I would be in favor of this proposal.

I’m not sure there is a great name for this. Since this pairs with the logical NOT operator, I would prefer the term negate. It would be possible to write !boolValue.toggle() and that wouldn’t be as clearly a double-negative as !boolBalue.negate(). I would also highly support the name not(). (Even given the number of jokes to be made at our expense.) When I read code to myself in my head, I pronounce the ! operator as “not.” I think it would be good if they shared a name.

The proposed method mutates and returns Void, so this shouldn't be possible.

So far on the thread, we've seen quite a few bikeshedding requests, which suggests the functionality isn't entirely clear or best named. (For example, negate/negated aren't bad choices here.) We've also seen people reaching for both mutating and non-mutating versions, to allow

  • when mutating, some.long.chain.of.access.toggle() replacing some.long.chain.of.access = !some.long.chain.of.access. This supports DRY, which is good if an esoteric use. Does this really pass the test of "If Swift were being designed today, would this be part of its stdlib?" There are some many @davedelong/MikeAsh/etc goodies I'd far prefer to see included.
  • when not mutating (currently out of scope for this proposal), simply negating, some.functional.chain.toggled() replaces !(some.functional.chain), putting the negation at the point and time of use. I guess this supports readability. One should certainly take care in linting to avoid let x = !(some.functional.chain.toggled()) as a likely bug. (And the compiler will surely catch let x = !(some.functional.chain.toggle()).

As I've stated before, I'm not hugely against this proposal, but I do think

  • one should avoid over-chaining (for example, where do breakpoints go?)
  • the stdlib should have a high barrier for inclusion
  • using let value = !(some.functional.chain) is not overly burdensome when chains are short. With parentheses, you emphasize negation right from the start of the chain, placing the emphasis on reversed logic that you wouldn't have in a trailing toggled().

I remain at "more meh than yeah".

5 Likes

+1 I don't see any negative impact, and I'm always in favour of standardizing common helpers many people will write. The optional chaining improvement is also great.

negate is the only alternate spelling I would consider. We don't have “logical inversion;” we have “logical negation.” But while that's the technically-correct term of art, it's probably a little confusable in common usage because people think of unary - as “negation.” The only real argument I could think of against toggle was that some people might view it as a cycle from on to off and back again (or vice versa) but the risk of that seems quite low.

3 Likes

+1 from me. My argument is that it is less terse than ! and that that is good.

I tend to avoid using ! because it is too terse. One thin, easy to overlook character literally negates the meaning of an expression.

(My only nit to pick is that I would also like toggled)

The review of this proposal is now over. The core team has decided to accept the proposal as-is. There was some discussion during the review of alternative names, but the team felt that toggle was the best one offered.

During the review, there was some discussion as to whether this kind of helper method belonged in the standard library. The core team sees the following motivations for its addition:

  • commonality: the team felt that the need to toggle a nested boolean is a common one across multiple different problem domains
  • readability: the addition of this command can significantly improve readability, especially as was seen in the example of toggling a boolean in a type held as a value in a dictionary
  • consistency: while reproducing the method in user code is fairly trivial, it is good to have a consistent way of doing this across all swift codebases, rather than having multiple variants
  • correctness: there is a correctness risk when the same long path needs to appear on both sides (especially when subscripts are involved), which this method would avoid
  • performance: this didn’t come up during the review, but a mutating member operation will be more efficient (requiring only one subscript lookup) once we have the co-routine-based accessors, planned for a future release

The core team would welcome further proposals to fill in gaps like this in the standard library.

6 Likes