@available and #available

Overview

  • There is an enum Engine in the framework which has a case only available iOS 27 onwards
  • I have an enum Car which uses the Engine in a switch statement

Question

  • Is there a better way to implement Car.engine?
  • Is there a way to define 2 Car types depending on if the iOS version is 27 or higher or if it is lower than 27?
  • Or is there an alternate approach to solving this?

Problem

  • Since Engine.electric and Car.green are only available iOS 27.0 onwards is there a way to avoid if #available(iOS 27.0, *) inside engine computed property?
  • The reason is I feel engine would never return hybrid but I just have it there to make it compile

Code

// Defined in the framework, I have no control over this
enum Engine {
    @available(iOS 27.0, *)
    case electric
    case combustion
    case hybrid
    case aircraftEngine
    case shipEngine
    // many more cases
}

// Type defined by me
enum Car {
    @available(iOS 27.0, *)
    case green
    case orange

    var engine: Engine {
        switch self {
        case .green:
            if #available(iOS 27.0, *) {
                .electric
            } else {
                .hybrid
            }
        case .orange:
            .combustion
        }
    }
}

Assuming it doesn't get reverted for some reason, with a future version of the Swift compiler you won't have to write if #available(iOS 27.0, *) in the body of case .green because the compiler will infer it for you. See #46662 (and the fix here).

Although looking more closely at your actual example, you're using a switch expression rather than a switch statement, which this enhancement doesn't work for yet. But I hope to address that in the same release.

In the meantime, you just have to write the if #available(iOS 27.0, *) in the case body.

1 Like

This would be huge, I’ve come across it multiple times, both with switch expressions and switch statements

1 Like

Thanks @tshortli, I am not sure if I am missing something.

Is this available in Swift 6.4 (Xcode 27)?

Following throws a compilation error:

I have taken the same example and changed to iOS 27 instead of macOS 26.

Error: 'f()' is only available in iOS 27.0 or newer

@available(iOS 27.0, *)
func f() -> Int { 0 }

enum E {
  @available(iOS 27.0, *)
  case a
}

func multiplex(_ e: E) -> Int {
  switch e {
  case .a:
    return f() // 'f()' is only available in iOS 27.0 or newer
  }
}

It's not in Swift 6.4. It should become available in the next release.

Edit: If you're curious, you could try with the latest development snapshot or Godbolt.

1 Like

Thanks a ton @tshortli this fix would be very useful!!!

Thanks a lot @tshortli that's a nice website to test different compiler versions.

Following code works fine with no compilation errors:

// Defined in the framework, I have no control over this
enum Engine {
    @available(iOS 27.0, *)
    case electric
    case combustion
    case hybrid
    case aircraftEngine
    case shipEngine
    // many more cases
}

// Type defined by me
enum Car {
    @available(iOS 27.0, *)
    case green
    case orange

    var engine: Engine {
        switch self {
        case .green:
            .electric
        case .orange:
            .combustion
        }
    }
}