Boolean comparison causes extremely slow compilation

No, not for operators on Boolean types.

Agreed on that, just want to "well, technically" a bit.

What is "well technically" about it? I wrote:

ah, didn't see that. Apparently my long term memory doesn't extend beyond 1 post :stuck_out_tongue:.

What does this mean? For optional Bool it's required to compare with ==. Do you mean it's not idiomatic for Bool but is idiomatic for Bool? ?

Actually I asked about this couple years back The Optional Truth

@Alejandro_Martinez (I think?) just wrote about this: https://twitter.com/alexito4/status/1321135571239014401

1 Like

This is every interesting! I'd suggest you use -Xfrontend -debug-constraints-on-line=<problematic-line> to dump the output of constraint solver for return because there is something going on here which I don't quite understand but looking at the output would help to determine which overload type-checker ended up picking. There is a performance optimization currently in place for cases where type on one size and result are know, it should bring (Bool, Bool) -> Bool overload to the top, so I'm wondering why that doesn't happen in this case...

5 Likes

iep that's me.

And ignoring the optionals in this conversation, I've always written == false. You may say is not idiomatic but in the majority of occasions is much easier to read and parse than a random ! in the middle of a string of characters. I sometimes wished modern languages took not expression instead of !.

It would make things much better for not a small number of codebases.

5 Likes

This is not a solution, but the code will be cleaner:

extension Optional where Wrapped == Bool {
     static prefix func !(value: Wrapped?) -> Bool {
          return value.map({ !$0 }) ?? false
     }
}

return !store.storage?.items.isEmpty

1 Like

Apparently a few of us prefer the explicit == false (myself included), so I wouldn’t say it’s some super-exotic way of writing things.

I’m sure we’re all very happy to see improvements to this area of the compiler. If there are hardcoded optimisations or heuristics, I hope they consider this.

I mean, OP’s grievance that compile times are > 40x slower using == is totally reasonable. “You’re writing it wrong” isn’t very helpful.

Moreover, your code turns !nil in to false. That is not “cleaner”. That’s the kind of alleged shortcut that makes code hard to read and leads to bugs.

The original function was with an optional, for example I added a standard value:

extension Optional where Wrapped == Bool {
        static prefix func !(value: Wrapped?) -> Bool? {
             return value.flatMap({ !$0 })
        }
   }

In any case, I agree that expanding the optional in advance will be a more correct.

Did you mean?

extension Optional where Wrapped == Bool {
  static prefic func !(value: Self) -> Self {
    value.map { $0 }
  }
}

Though I still wouldn't recommend it. It's not clear what you'd mean if you write:

!value ?? false

Chiming in specifically to disagree with this. An explicit comparison is, IMO, always more expressive than an easily missed ! or having to remember the type of a value.

So while it may not be commonly used, I would argue very strenuously that it is far more expressive and thus should be considered idiomatic.

(In my feverish pipe dreams of "if I could re-do swift", I fantasize about ditching the ! operator entirely)

9 Likes

In C, where all boolean tests are explicitly or implicitly comparisons, boolean tests are a footgun for the unwary. (harm: -100)

In Swift, where boolean tests are not comparisons, boolean tests are (to some) less expressive. (harm: -1)

As with many other "opinionated" Swift features, surely the footgun wins the argument for the other side. :slight_smile:

Not to mention that if o == false { … } is the same footgun as C, if o is a Bool?. (It turns binary logic into ternary logic, and would you bet your toes on noticing?)

Also, for the record, I want to speak up for the … dozens, or more … people in the world who think that ! is adequately readable.

1 Like

I’m not seeing where you’re disagreeing. I described what is and how it came to be. Whether it should be something else is a different point and rather non-salient to the question asked here: Why is it slow to typecheck expressions with operators and literal operands, and how can users make the typechecking of such code faster? It is slow for the reasons outlined above, and writing an alternative form makes typechecking faster.

We have had plenty of threads about the spelling of the ! operator, and it doesn’t need to be rehashed here.

@DeskA Have you ever tried with this?

return false == items.isEmpty

Another suggestion, try to make explicit the type of false in your comparison:

public override func hasItems(in: Store) -> Bool {
    guard let items = store.storage?.items else { return false }
    return items.isEmpty == Bool(false)
}

Or with (false as Bool).