10

I'm building source code using an Xcode project that has its "Swift Language Version" set to "Swift 4." Even with this set, the project builds Swift 5.1 source code like, for example, implicit returns and Swift 5 source code using the new isMultiple(of:) method.

The Swift 5 and 5.1 code still works even with "Swift Language Version" set to "Swift 4" or "Swift 4.2"

It's only when running #elseif swift(>=4.1) statements that there appears to be a difference (code from https://stackoverflow.com/a/46080904/414415). Those results output their expected results.

However, I'm left wondering, how does the my Swift 5 source code compile successfully when the build setting clearly states Swift 4? And if the setting does not change which version of Swift I can use, what does it actually do?

Ilias Karim
  • 4,798
  • 3
  • 38
  • 60
  • 1
    "what does it actually do?" The use case is roughly the opposite of what you are doing, namely, that you are coming from an earlier version of Xcode with e.g. Swift 4.2, and something that was legal there is no longer legal in _this_ version of Xcode with Swift 5.1. So in that situation you would leave the target language version set at Swift 4.2 until you are ready to migrate it forward to Swift 5. – matt Feb 13 '20 at 19:42

1 Answers1

11

Prior to Swift 4, the version of the compiler and the language were one and the same. But since Swift 4, the compiler can run in a compatibility mode for previous Swift versions. check more info on compatibility modes in the Swift 4.0 release notes

The Xcode build setting SWIFT_VERSION set's the compiler flag -swift-version which is the language mode. From the swift compiler print out below this parameter only changes how the input is interpreted.

swiftc -h|grep 'Swift language version number'
  -swift-version <vers>   Interpret input according to a specific Swift language version number

Thus When you select Swift Language Version to 4.2, this does not mean use Swift 4.2 compiler. The compiler version will still be 5.1.3, the Swift Language Version setting instructs the compiler to run in Swift 4.2 compatibility mode. The compatibility mode means you may not need to modify your swift 4.2 code to use the new version of the compiler. Because the compiler running in compatibility mode allows Swift version 4.2 code to compile and run alongside code from version 5 and later.

compiler options

The Swift 5 compiler with compatibility mode can compile code written with either Swift 4 syntax, Swift 4.2 syntax, or Swift 5 syntax.

Here is a code example, create a file test.swift with code below:

//code written before siwft 5
let firstName = "michael jackson"
let offset = firstName.endIndex.encodedOffset

// Check swift version being used.
#if swift(>=5.2)
print("Hello, Swift 5.2")

#elseif swift(>=5.1)
print("Hello, Swift 5.1")

#elseif swift(>=5.0)
print("Hello, Swift 5.0")

#elseif swift(>=4.2)
print("Hello, Swift 4.2")

#elseif swift(>=4.1)
print("Hello, Swift 4.1")

#elseif swift(>=4.0)
print("Hello, Swift 4.0")

#endif

suppose the above code was written before swift 5 using the swift 4 compiler this code will compile with no error's as shown below.

enter image description here

After swift 5 is released if you try to compile this code with Swift 5 compiler as shown below.

Swift 5 compiler

You will get the warning shown above since encodedOffset is deprecated in swift 5.

You could downgrade and use the swift 4 compiler or you can use the Swift 5 compiler in compatibility mode with the compiler flag -swift-version as shown below.

Swift 5 compiler with compatibility mode

It's important to note that Swift 4 compiler, and the Swift 5 compiler in Swift-4 compatibility mode are not the same thing. New swift 5 language features are normally available to the swift 5 compiler running compatibility mode. This allows developers to use the new features even when they can't upgrade to swift 5. The new Swift 5 features will not be available to the Swift 4 compiler.

byaruhaf
  • 4,128
  • 2
  • 32
  • 50
  • 1
    Your explanation makes sense to me. What still doesn't make sense is how come setting Swift Language Version to 4 or 4.2 does not throw errors instead of compiling Swift 5 and 5.1 syntax. It seems like it should throw errors. – Ilias Karim Feb 12 '20 at 15:42
  • 1
    I have updated the explanation, does it answer why no errors are thrown. – byaruhaf Feb 12 '20 at 21:44
  • 1
    It would help a lot if you could demonstrate an example. I tried a couple of Swift 4.2 and Swift 4 features that were deprecated and setting the "Swift Language Version" to the version that supported those features did nothing to remove build errors and warnings. They appeared just as when building with the "Swift Language Version" set to Swift 5. – Ilias Karim Feb 13 '20 at 15:00
  • 1
    Updated the explanation, with a code example with swift 4 code, using both the swift 4 compiler and swift 5 compiler. – byaruhaf Feb 13 '20 at 17:06
  • 1
    Might help to look at the table in https://github.com/apple/swift-evolution/blob/master/proposals/0212-compiler-version-directive.md. Distinguish between language version and compiler version. – matt Feb 13 '20 at 19:43
  • Your example helps a lot @byaruhaf. What sort of language features, if any, require running the Swift 5 compiler with Swift 5 "Swift Language Version?" – Ilias Karim Feb 14 '20 at 16:41
  • Swift 5 compiler with Swift 5 "Swift Language Version?" is the default mode check out this link from matt above, you can see from the table "--swift-version 5" on a swift 5.1 compiler is just swift 5.1. basically Language Version is mostly used to make older code compile with new compilers. – byaruhaf Feb 14 '20 at 17:07
  • Also, note that language features marked with `@available(swift 5.1)` can only be used by Swift 5 compiler with Swift 5 "Swift Language Version – byaruhaf Feb 14 '20 at 17:22