Ability to exclude certain platforms in #availability check

It is the first time I am contributing here, so please excuse me in advance if I didn't understand the process correctly.

Recently, I stumbled upon an issue. I wanted to make some code available on iOS starting from iOS 13, so, naturally, I used the following check:

    if #available(iOS 13.0, *) {
        //CODE HERE
    } else {
        //Fallback
    }

I then needed to reuse this code in a macOS app and to my surprise, it passed the availability check above. It is not convenient and I think it would be great if the availability check could be enhanced and it would be possible to indicate platforms to exclude. For example:

#available(iOS 13.0, !macOS, *)

What do you think?

That wouldn't really solve your problem. Even if you excluded macOS, it still wouldn't behave correctly on linux, windows, fridgeOS, etc

1 Like

Wouldn't it be possible to allow the #available command to exclude all of the OSs which it currently support? I was using macOS only as an example. I think it should allow us to exclude any OS which it currently allows us to check.

Wouldn't it be easier to write that you want this code to run on iOS if you "wanted to make some code available on iOS starting from iOS 13", instead of writing that you don't want it running on macOS? That way you wouldn't forget to add new operating systems in the future.

Anyway, the thing you want is possible today, but awkward because it combines compile-time and runtime checks

#if os(macOS)
let isRunningMacOS = true
#else
let isRunningMacOS = false
#endif
if !isRunningMacOS, #available(iOS 13.0, *) {
    //CODE HERE
} else {
    //Fallback
}
1 Like

Thank you, I like your method. Still, I believe it would be a welcome addition to #available check, but given the simplicity of your approach it may not be top-priority

Perhaps this is acceptable too:

#available(iOS 13.0, macOS 9999, *)

Well, when you use availability checks, you’re checking against annotated OS libraries. If the compiler allows the conditionally-available code on the Mac, it means that functionality is present in the OS libraries and is able to be used.

So I guess my question is: why would you want to disable functionality which can work on the Mac?

For what it's worth, the decision to permit unmentioned OSs was very deliberate: it was born from experience with bringing up tvOS and finding that everybody who had checked for "iOS 9 or later" had unintentionally excluded tvOS. For this reason, Apple actually changed the Objective-C compiler so that availability for versions of iOS before tvOS existed would also be applied to tvOS unless explicitly marked unavailable.* The lesson we learned was that availability should not restrict new, unknown platforms like cukr's fridgeOS, and then because you can't tell if a particular file's code was written before or after the introduction of fridgeOS, that basically means availability should not restrict any OS that's not explicitly forbidden. That's what the , * is supposed to mean at the end of the availability declartion: it's "and anything else", inspired by shell wildcard syntax.

That said, I can't think of any reason why adding an explicit !macOS would be a problem, even if it's not something commonly needed. On the attribute form of availability it would expand into @availability(macOS, unavailable) with no message; for #available it would mark dead code. (We could even do a first-pass implementation using Michel's macOS 9999.) We'd have to decide whether the compiler still required the code in the if branch to be valid even though it was known-dead, but that would just need discussion.

* I don't actually remember if this is precisely what we did, but it was something like this. ("we" because I was at Apple at the time.)

4 Likes