What’s new in Swift 5.0
What’s new in Swift 5.0
Learn about the key features available in Swift 5.0, The primary goal of Swift 5.0 is for the language to achieve ABI stability. This will enable a stable Swift runtime to be deployed by OS vendors that can be linked against by executables and libraries.
New Improvements in Swift 5:
- Enhancing String Literals Delimiters to Support Raw Text (SE-0200)
- Add Result to the Standard Library (SE-0235)
- Fix
ExpressibleByStringInterpolation
(SE-0228) - Introduce user-defined dynamically “callable” types (SE-0216)
- Handling Future Enum Cases (SE-0192)
- Flatten nested optionals resulting from ‘try?’ (SE-0230)
- Adding
isMultiple
toBinaryInteger
(SE-0225)
Special Note:
- Swift apps no longer include dynamically linked libraries for the Swift standard library and Swift SDK overlays in build variants for devices running iOS 12.2, watchOS 5.2, and tvOS 12.2. As a result, Swift apps can be smaller when deployed for testing using TestFlight, or when thinning an app archive for local development distribution.
- To reduce the size taken up by Swift metadata, convenience initializers defined in Swift now only allocate an object ahead of time if they’re calling a designated initializer defined in Objective-C.
Read these notes on improvements to get in-depth knowledge to enhance your knowledge on whats upcoming in swift.
Enhancing String Literals Delimiters to Support Raw Text (SE-0200)
Expanding Delimiters
Our design adds customizable string delimiters. You may pad a string literal with one or more #
(pound, Number Sign, U+0023) characters:
"This is a Swift string literal"
#"This is also a Swift string literal"#
Customized Escape Delimiters
Strings using custom boundary delimiters mirror their pound sign(s) after the leading backslash, as in these examples which produce identical results to the preceding string literal:
#"This string has an \#(interpolated) item"#
####"This string has an \####(interpolated) item"####
Add Result to the Standard Library
Result<Success, Failure>
is a pragmatic compromise between competing error handling concerns both present and future.
Usage
Asynchronous APIs
This can make it quite difficult to elegantly consume the results of these APIs:
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard error != nil else { self.handleError(error!) }
guard let data = data, let response = response else { return // Impossible? }
handleResponse(response, data: data)
}
While this code is only a few lines long, it exposes Swift’s complete lack of automatic error handling for asynchronous APIs. Not only was the error
forcibly unwrapped (or perhaps handled using a slightly less elegant if
statement), but a possibly impossible scenario was created. What happens if response
or data
are nil
? Is it even possible? It shouldn't be, but Swift currently lacks the ability to express this impossibility. Using Result
for the same scenario allows for much more elegant code:
URLSession.shared.dataTask(with: url) { (result: Result<(response: URLResponse, data: Data), Error>) in // Type added for illustration purposes.
switch result {
case let .success(success):
handleResponse(success.response, data: success.data)
case let .error(error):
handleError(error)
}
}
This API expresses exactly the intended result (either an error or data and response, never all or none) and allows them to be handled much more clearly.
Separating Errors
It’s occasionally useful to be able to run throw
able functions in such way as to allow the developer to disambiguate between the sources of the errors, especially if the errors don't contain the information necessary to do so, or the developer doesn't want to implement such a check. For instance, if we needed to disambiguate between the errors possible when reading files:
do {
handleOne(try String(contentsOfFile: oneFile))
} catch {
handleOneError(error)
}
This case can be expressed much more clearly using Result
:
let one = Result { try String(contentsOfFile: oneFile) }
handleOne(one)
Additional convenience API on Result
could make many of these cases even more elegant.
Fix ExpressibleByStringInterpolation
An interpolated string literal contains one or more embedded expressions, delimited by \(
and )
. At runtime, these expressions are evaluated and concatenated with the string literal to produce a value. They are typically more readable than code that switches between string literals, concatenation operators, and arbitrary expressions.
An interpolated string will be converted into code that:
- Initializes an instance of an associated
StringInterpolation
type, passing the total literal segment size and interpolation count as parameters. - Calls its
appendLiteral(_:)
method to append literal values, andappendInterpolation
to append its interpolated values, one at a time. Interpolations are treated as call parentheses—that is,\(x, with: y)
becomes a call toappendInterpolation(x, with: y)
. - Passes the instance to
init(stringInterpolation:)
to produce a final value.
Below is code roughly similar to what the compiler would generate:
// Semantic expression for: "hello \(name)!"
String(stringInterpolation: {
var temp = String.StringInterpolation(literalCapacity: 7, interpolationCount: 1)
temp.appendLiteral("hello ")
temp.appendInterpolation(name)
temp.appendLiteral("!")
return temp
}())
Introduce user-defined dynamically “callable” types
This is a follow-up to SE-0195 — Introduce User-defined “Dynamic Member Lookup” Types, which shipped in Swift 4.2. It introduces a new @dynamicCallable
attribute, which marks a type as being "callable" with normal syntax. It is simple syntactic sugar which allows the user to write:
a = someValue(keyword1: 42, "foo", keyword2: 19)
and have it be rewritten by the compiler as:
a = someValue.dynamicallyCall(withKeywordArguments: [
"keyword1": 42, "": "foo", "keyword2": 19
])
Handling Future Enum Cases
When switching over a non-frozen enum, the switch statement that matches against it must include a catch-all case (usually default
or an "ignore" _
pattern).
switch excuse {
case .eatenByPet:
// …
case .thoughtItWasDueNextWeek:
// …
}
Failure to do so will produce a warning in Swift 5. A program will trap at run time if an unknown enum case is actually encountered.
Here’s a more complicated example:
switch excuse {
case .eatenByPet:
// Specific known case
@unknown case _:
// Any cases not recognized by the compiler
case _:
// Any other cases the compiler *does* know about,
// such as .thoughtItWasDueNextWeek
}
Flatten nested optionals resulting from ‘try?’
In Swift 5, try? someExpr()
will mirror the behavior of foo?.someExpr()
:
- If
someExpr()
produces a non-optional value, it will be wrapped in an Optional. - If
someExpr()
produces anOptional
, then no additional optional-ness is added.
This results in the following changes to the type of a try?
expression:
// Swift 4: 'Int??'
// Swift 5: 'Int?'
let result = try? database?.countOfRows(matching: predicate)
// Swift 4: 'String??'
// Swift 5: 'String?'
let myString = try? String(data: someData, encoding: .utf8)
// Swift 4: '[String: Any]??'
// Swift 5: '[String: Any]?'
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
There are no changes to the overall type when the sub-expression produces a non-optional.
Adding isMultiple
to BinaryInteger
Swift 5 adds func isMultiple(of other: Self) -> Bool
to the BinaryInteger
protocol.
// KeyPath.swift in apple/swift
_sanityCheck(bytes > 0 && bytes.isMultiple(of: 4), "capacity must be multiple of 4 bytes")
Swift 5.0 is the latest release of Swift, but previous swift releases have been packed with great features too.
Hope this article is useful for people looking to find out whats new in upcoming version of swift, Please ❤️ to recommend this post to others 😊. Let me know your feedback. :)
References:-
- https://github.com/apple/swift-evolution/blob/master/proposals/0200-raw-string-escaping.md
- https://github.com/apple/swift-evolution/blob/master/proposals/0235-add-result.md
- https://github.com/apple/swift-evolution/blob/master/proposals/0228-fix-expressiblebystringinterpolation.md
- https://github.com/apple/swift-evolution/blob/master/proposals/0216-dynamic-callable.md
- https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
- https://github.com/apple/swift-evolution/blob/master/proposals/0230-flatten-optional-try.md
- https://github.com/apple/swift-evolution/blob/master/proposals/0225-binaryinteger-iseven-isodd-ismultiple.md