Repository: twostraws/whats-new-in-swift-4-1
Branch: main
Commit: 26bcc8fbb688
Files: 11
Total size: 21.8 KB
Directory structure:
gitextract_5g1yjty1/
├── .gitignore
├── README.md
└── Whats-New-In-Swift-4-1.playground/
├── Pages/
│ ├── Build configuration import testing.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Conditional conformances.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Introduction.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Key decoding strategy in Codable.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Recursive constraints on associated types.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Synthesized Equatable and Hashable.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Target environment testing.xcplaygroundpage/
│ │ └── Contents.swift
│ └── flatMap() is now (partly) compactMap().xcplaygroundpage/
│ └── Contents.swift
└── contents.xcplayground
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcshareddata/
xcuserdata/
## Other
.DS_Store
*.moved-aside
*.xccheckout
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
================================================
FILE: README.md
================================================
# What’s new in Swift 4.1?
This is an Xcode playground that demonstrates the new features introduced in Swift 4.1:
* Synthesized `Equatable` and `Hashable`
* Key decoding strategy in `Codable`
* Conditional conformances
* Recursive constraints on associated types
* Build configuration import testing
* Target environment testing
* `flatMap()` is now (partly) `compactMap()`
This is designed to complement my existing article [What’s New in Swift 4.1](https://www.hackingwithswift.com/articles/50/whats-new-in-swift-4-1). You might also want to check out [What's New in Swift 4.2](https://www.hackingwithswift.com/articles/77/whats-new-in-swift-4-2) and its [accompanying playground](https://github.com/twostraws/whats-new-in-swift-4-2). Alternatively, I have a whole website dedicated to tracking [what's new in Swift](https://www.whatsnewinswift.com) – you should check it out at <https://www.whatsnewinswift.com>.
If you hit problems or have questions, you're welcome to tweet me [@twostraws](https://twitter.com/twostraws) or email <paul@hackingwithswift.com>.
**Note:** This playground requires Swift 4.1, so you should have installed Xcode 9.3 or later. This is available through the [Mac App Store](https://itunes.apple.com/gb/app/xcode/id497799835?mt=12) or direct from <https://developer.apple.com/download>.

================================================
FILE: Whats-New-In-Swift-4-1.playground/Pages/Build configuration import testing.xcplaygroundpage/Contents.swift
================================================
/*:
[< Previous](@previous) [Home](Introduction) [Next >](@next)
## Build configuration import testing
Swift 4.1 implements [SE-0075](https://github.com/apple/swift-evolution/blob/master/proposals/0075-import-test.md), which introduces a new `canImport` condition that lets us check whether a specific module can be imported when our code is compiled.
This is particularly important for cross-platform code: if you had a Swift file that implemented one behavior on macOS and another on iOS, or if you needed specific functionality for Linux.
For example:
*/
#if canImport(SpriteKit)
// this will be true for iOS, macOS, tvOS, and watchOS
#else
// this will be true for other platforms, such as Linux
#endif
/*:
Previously you would have had to use inclusive or exclusive tests by operating system, like this:
*/
#if !os(Linux)
// Matches macOS, iOS, watchOS, tvOS, and any other future platforms
#endif
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
// Matches only Apple platforms, but needs to be kept up to date as new platforms are added
#endif
/*:
The new `canImport` condition lets us focus on the functionality we care about rather than what platform we're compiling for, thus avoiding a variety of problems.
[< Previous](@previous) [Home](Introduction) [Next >](@next)
*/
================================================
FILE: Whats-New-In-Swift-4-1.playground/Pages/Conditional conformances.xcplaygroundpage/Contents.swift
================================================
/*:
[< Previous](@previous) [Home](Introduction) [Next >](@next)
## Conditional conformances
Swift 4.1 implements [SE-0143](https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md), which introduced proposed conditional conformances into the language. This allows types to conform to a protocol only when certain conditions are met.
To demonstrate conditional conformances, let's create a `Purchaseable` protocol that we can use to buy things:
*/
protocol Purchaseable {
func buy()
}
/*:
We can now define a `Book` struct that conforms to the protocol, and prints a message when a book is bought:
*/
struct Book: Purchaseable {
func buy() {
print("You bought a book")
}
}
/*:
So far this is easy enough, but let's take it one step further: what if the user has a basket full of books, and wants to buy them all?
We could loop over all books in the array by hand, calling `buy()` on each one. But a better approach is to write an extension on `Array` to make it conform to `Purchaseable`, then give it a `buy()` method that in turn calls `buy()` on each of its elements.
This is where conditional conformances come in: if we tried to extend all arrays, we'd be adding functionality where it wouldn't make sense – we'd be adding `buy()` to arrays of strings, for example, even though those strings don't have a `buy()` method we can call.
Swift 4.1 lets us make arrays conform to `Purchaseable` only if their elements also conform to `Purchaseable`, like this:
*/
extension Array: Purchaseable where Element: Purchaseable {
func buy() {
for item in self {
item.buy()
}
}
}
/*:
As you can see, conditional conformances let us constrain the way our extensions are applied more precisely than was possible before.
Conditional conformances also make large parts of Swift code easier and safer, even if you don't do any extra work yourself. For example, this code creates two arrays of optional strings and checks whether they are equal:
*/
var left: [String?] = ["Andrew", "Lizzie", "Sophie"]
var right: [String?] = ["Charlotte", "Paul", "John"]
left == right
/*:
That might seem trivial, but that code wouldn't even compile in Swift 4.0 – both `String` and `[String]` were equatable, but `[String?]` was not.
The introduction of conditional conformance in Swift 4.1 means that it’s now possible to add protocol conformance to a type as long as it satisfies a condition.
In this case, if the elements of the array are equatable, that means the whole thing is equatable. So, the above code now compiles in Swift 4.1
Conditional conformance has been extended to the `Codable` protocol in a way that will definitely make things safer. For example:
*/
import Foundation
struct Person {
var name = "Taylor"
}
var people = [Person()]
var encoder = JSONEncoder()
// try encoder.encode(people)
/*:
If you uncomment the `encoder.encode(people)` line, Swift will refuse to build your code because you're trying to encode a struct that doesn't conform to `Codable`.
However, that code compiled cleanly with Swift 4.0, then threw a fatal error at runtime because `Person` doesn’t conform to `Codable`.
Obviously no one wants a fatal error at runtime, because it means your app crashes. Fortunately, Swift 4.1 cleans this up using conditional conformances: `Optional`, `Array`, `Dictionary`, and `Set` now only conform to `Codable` if their contents also conform to `Codable`, so the above code will refuse to compile.
[< Previous](@previous) [Home](Introduction) [Next >](@next)
*/
================================================
FILE: Whats-New-In-Swift-4-1.playground/Pages/Introduction.xcplaygroundpage/Contents.swift
================================================
/*:
# What’s new in Swift 4.1
* Created by [Paul Hudson](https://twitter.com/twostraws) – [Hacking with Swift](https://www.hackingwithswift.com)
* Last update: April 4th 2018
This playground is designed to showcase new features introduced with Swift 4.1. I already [wrote an article on it](https://www.hackingwithswift.com/articles/50/whats-new-in-swift-4-1), but it's a lot more fun to see things in action and experiment yourself.
If you hit problems or have questions, you're welcome to tweet me [@twostraws](https://twitter.com/twostraws) or email <paul@hackingwithswift.com>.
- important: This playground requires **Xcode 9.3** or later, but if you're stuck on an older version you can [install a Swift toolchain](https://swift.org/download/) for your current Xcode version and use that instead.
## Contents
* [Synthesized `Equatable` and `Hashable`](Synthesized%20Equatable%20and%20Hashable)
* [Key decoding strategy in `Codable`](Key%20decoding%20strategy%20in%20Codable)
* [Conditional conformances](Conditional%20conformances)
* [Recursive constraints on associated types](Recursive%20constraints%20on%20associated%20types)
* [Build configuration import testing](Build%20configuration%20import%20testing)
* [Target environment testing](Target%20environment%20testing)
* [`flatMap()` is now (partly) `compactMap()`](flatMap()%20is%20now%20(partly)%20compactMap())
[Next >](@next)
*/
================================================
FILE: Whats-New-In-Swift-4-1.playground/Pages/Key decoding strategy in Codable.xcplaygroundpage/Contents.swift
================================================
/*:
[< Previous](@previous) [Home](Introduction) [Next >](@next)
## Key decoding strategy in `Codable`
The `Codable` protocol, introduced in Swift 4.0, is the fastest and easiest way of converting your data types to JSON and back again. However, often you'd hit a problem where `Codable` wasn't quite as easy as you had hoped: if your JSON used snake_case for its key names and your Swift code used camelCase for its matching property names, `Codable` wouldn’t be able to convert between the two. Instead, you needed to create your own `CodingKeys` mapping to explain how the two matched up.
Swift 4.1 solves this problem by introducing a new `keyDecodingStrategy` property on `JSONDecoder` that can automatically convert between snake_case and camelCase if you need it. The inverse property, `keyEncodingStrategy`, also exists on `JSONEncoder` so you can convert your Swift camelCase names back into snake_case.
Let's look at a practical example – this code creates some sample JSON, then converts it into a `Data` instance:
*/
import Foundation
let jsonString = """
[
{
"name": "MacBook Pro",
"screen_size": 15,
"cpu_count": 4
},
{
"name": "iMac Pro",
"screen_size": 27,
"cpu_count": 18
}
]
"""
let jsonData = Data(jsonString.utf8)
/*:
That stores an array of two items, each describing a Mac. As you can see, both `screen_size` and `cpu_count` use snake_case – words are all lowercased, with underscores separating them.
Now, we want to convert that JSON into an array of `Mac` instances using this struct:
*/
struct Mac: Codable {
var name: String
var screenSize: Int
var cpuCount: Int
}
/*:
That follows standard Swift naming conventions, so the property names are all camelCased – words have no separators, but second and subsequent words all start with a capital letter.
Using the new `keyDecodingStrategy` of `JSONDecoder` we can convert our sample JSON into a `[Mac]` array like this:
*/
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let macs = try decoder.decode([Mac].self, from: jsonData)
print(macs)
} catch {
print(error.localizedDescription)
}
/*:
When you want to go back the other way – to convert a Codable struct with camelCase properties back to JSON with snake_case keys, set the `keyEncodingStrategy` property of your `JSONEncoder` to `.convertToSnakeCase` like this:
*/
if let macs = try? decoder.decode([Mac].self, from: jsonData) {
// now we have an array to work with, convert it back into JSON
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let encoded = try encoder.encode(macs)
print(encoded.count)
}
/*:
[< Previous](@previous) [Home](Introduction) [Next >](@next)
*/
================================================
FILE: Whats-New-In-Swift-4-1.playground/Pages/Recursive constraints on associated types.xcplaygroundpage/Contents.swift
================================================
/*:
[< Previous](@previous) [Home](Introduction) [Next >](@next)
## Recursive constraints on associated types
Swift 4.1 implements [SE-0157](https://github.com/apple/swift-evolution/blob/master/proposals/0157-recursive-protocol-constraints.md), which lifts restrictions on the way we use associated types inside protocols. As a result, we can now create recursive constraints for our associated types: associated types that are constrained by the protocol they are defined in.
To demonstrate this, let's consider a simple team hierarchy in a tech company. In this company, every employee has a manager – someone more senior to them that they report to. Each manager must also be an employee of the company, because it would be weird if they weren't.
We can express this relationship in a simple `Employee` protocol:
*/
protocol Employee {
associatedtype Manager: Employee
var manager: Manager? { get set }
}
/*:
- note: I've used an optional `Manager?` because ultimately one person (presumably the CEO) has no manager.
Even though that's a fairly self-evident relationship, it wasn't possible to compile that code in Swift 4.0 because we're using the `Employee` protocol inside itself.
However, this is fixed in Swift 4.1 because of the new ability to use recursive constraints on associated types.
Thanks to this new feature, we can model a simple tech company that has three kinds of team members: junior developers, senior developers, and board members.
The reporting structure is also simple: junior developers are managed by senior developers, senior developers are managed by board members, and board members may be managed by another board member – e.g. the CTO reporting to the CEO.
That looks exactly as you would imagine thanks to Swift 4.1:
*/
class BoardMember: Employee {
var manager: BoardMember?
}
class SeniorDeveloper: Employee {
var manager: BoardMember?
}
class JuniorDeveloper: Employee {
var manager: SeniorDeveloper?
}
/*:
- note: I've used classes here rather than structs because `BoardMember` itself contains a `BoardMember` property and that would result in an infinitely sized struct. If one of these has to be a class I personally would prefer to make all three classes just for consistency, but if you preferred you could leave `BoardMember` as a class and make both `SeniorDeveloper` and `JuniorDeveloper` into structs.
[< Previous](@previous) [Home](Introduction) [Next >](@next)
*/
================================================
FILE: Whats-New-In-Swift-4-1.playground/Pages/Synthesized Equatable and Hashable.xcplaygroundpage/Contents.swift
================================================
/*:
[< Previous](@previous) [Home](Introduction) [Next >](@next)
## Synthesized `Equatable` and `Hashable`
The `Equatable` protocol allows Swift to compare one instance of a type against another. When we say 5 == 5, Swift understands what that means because `Int` conforms to `Equatable`, which means it implements a function describing what `==` means for two instances of `Int`.
Implementing `Equatable` in our own value types allows them to work like Swift’s strings, arrays, numbers, and more, and it’s usually a good idea to make your structs conform to `Equatable` just so they fit the concept of value types better.
Swift 4.1 implements [SE-0185](https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md), which allows the compiler to synthesize conformance for `Equatable` – it can generate an `==` method automatically, which will compare all properties in one value with all properties in another.
All you have to do is add `Equatable` to your type, and Swift can take care of the rest. For example:
*/
struct Person: Equatable {
var firstName: String
var lastName: String
var age: Int
}
let paul = Person(firstName: "Paul", lastName: "Hudson", age: 38)
let joanne = Person(firstName: "Joanne", lastName: "Rowling", age: 52)
if paul == joanne {
print("These people match")
} else {
print("No match")
}
/*:
Of course, if you *want* you can implement `==` yourself. For example, if your type has an `id` property that identifies it uniquely, you would write `==` to compare that single value rather than letting Swift do all the extra work of comparing all properties.
In this next example, each instance of `User` has a variety of properties that the default implementation of `==` would have to compare in order to check whether two objects are equal. However, by adding our own `==` implementation we can check a property we know is unique:
*/
struct User: Equatable {
var id: Int
var username: String
var password: String
var jobTitle: String
var firstName: String
var lastName: String
static func ==(lhs: User, rhs: User) -> Bool {
return lhs.id == rhs.id
}
}
/*:
Swift 4.1 also introduces synthesized support for the `Hashable` protocol, which means it will generate a `hashValue` property for conforming types automatically. `Hashable` was always annoying to implement because you need to return a unique (or at least mostly unique) hash for every object. It’s important, though, because it lets you use your objects as dictionary keys and store them in sets.
Previously we’d need to write code like this:
*/
extension User: Hashable {
var hashValue: Int {
return firstName.hashValue ^ lastName.hashValue &* 16777619
}
}
/*:
For the most part that’s no longer needed in Swift 4.1: just adding the `Hashable` protocol to your type will ask the Swift compiler to generate the `hashValue` property for you. As with `Equatable`, you can still write your own code if there’s something specific you need.
- note: You still need to opt in to these protocols by adding a conformance to your type, and using the synthesized code does require that all properties in your type conform to `Equatable` or `Hashable` respectively.
[< Previous](@previous) [Home](Introduction) [Next >](@next)
*/
================================================
FILE: Whats-New-In-Swift-4-1.playground/Pages/Target environment testing.xcplaygroundpage/Contents.swift
================================================
/*:
[< Previous](@previous) [Home](Introduction) [Next >](@next)
## Target environment testing
Swift 4.1 implements [SE-0190](https://github.com/apple/swift-evolution/blob/master/proposals/0190-target-environment-platform-condition.md), which introduces a new `targetEnvironment` condition that lets us differentiate between builds that are for physical devices and those that are for a simulated environment.
At this time `targetEnvironment` has only one value, `simulator`, which will be true if your build is targeting a simulated device such as the iOS Simulator.
For example:
*/
#if targetEnvironment(simulator)
// code for the simulator here
#else
// code for real devices here
#endif
/*:
This is useful when writing code to deal with functionality the simulator doesn't support, such as capturing photos from a camera or reading the accelerometer.
As an example, let's look at processing a photo from the camera. If we're running on a real device we'll create and configure a `UIImagePickerController()` to take photos using the camera, but if we're in the simulator we'll just load a sample image from our app bundle:
*/
import UIKit
class TestViewController: UIViewController, UIImagePickerControllerDelegate {
// a method that does some sort of image processing
func processPhoto(_ img: UIImage) {
// process photo here
}
// a method that loads a photo either using the camera or using a sample
func takePhoto() {
#if targetEnvironment(simulator)
// we're building for the simulator; use the sample photo
if let img = UIImage(named: "sample") {
processPhoto(img)
} else {
fatalError("Sample image failed to load")
}
#else
// we're building for a real device; take an actual photo
let picker = UIImagePickerController()
picker.sourceType = .camera
vc.allowsEditing = true
picker.delegate = self
present(picker, animated: true)
#endif
}
// this is called if the photo was taken successfully
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// hide the camera
picker.dismiss(animated: true)
// attempt to retrieve the photo they took
guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else {
// that failed; bail out
return
}
// we have an image, so we can process it
processPhoto(image)
}
}
/*:
[< Previous](@previous) [Home](Introduction) [Next >](@next)
*/
================================================
FILE: Whats-New-In-Swift-4-1.playground/Pages/flatMap() is now (partly) compactMap().xcplaygroundpage/Contents.swift
================================================
/*:
[< Previous](@previous) [Home](Introduction)
## `flatMap()` is now (partly) `compactMap()`
The `flatMap()` method was useful for a variety of things in Swift 4.0, but one was particularly popular: the ability to transform each object in a collection, then remove any items that were nil afterwards
Swift Evolution proposal [SE-0187](https://github.com/apple/swift-evolution/blob/master/proposals/0187-introduce-filtermap.md) suggested changing this, and as of Swift 4.1 this `flatMap()` variant has been renamed to `compactMap()` to make its meaning clearer.
For example:
*/
let array = ["1", "2", "Fish"]
let numbers = array.compactMap { Int($0) }
print(numbers)
/*:
That will create an `Int` array containing the numbers 1 and 2, because "Fish" will fail conversion to Int, return nil, and be ignored.
- note: To avoid confusion, it's worth adding that only this specific usage `flatMap()` has been renamed to `compactMap()` – the `flatMap()` method still retains its other behaviors.
[< Previous](@previous) [Home](Introduction)
*/
================================================
FILE: Whats-New-In-Swift-4-1.playground/contents.xcplayground
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='6.0' target-platform='ios' display-mode='rendered'>
<pages>
<page name='Introduction'/>
<page name='Synthesized Equatable and Hashable'/>
<page name='Key decoding strategy in Codable'/>
<page name='Conditional conformances'/>
<page name='Recursive constraints on associated types'/>
<page name='Build configuration import testing'/>
<page name='Target environment testing'/>
<page name='flatMap() is now (partly) compactMap()'/>
</pages>
</playground>
gitextract_5g1yjty1/
├── .gitignore
├── README.md
└── Whats-New-In-Swift-4-1.playground/
├── Pages/
│ ├── Build configuration import testing.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Conditional conformances.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Introduction.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Key decoding strategy in Codable.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Recursive constraints on associated types.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Synthesized Equatable and Hashable.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Target environment testing.xcplaygroundpage/
│ │ └── Contents.swift
│ └── flatMap() is now (partly) compactMap().xcplaygroundpage/
│ └── Contents.swift
└── contents.xcplayground
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (24K chars).
[
{
"path": ".gitignore",
"chars": 1472,
"preview": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n"
},
{
"path": "README.md",
"chars": 1404,
"preview": "# What’s new in Swift 4.1?\n\nThis is an Xcode playground that demonstrates the new features introduced in Swift 4.1: \n\n* "
},
{
"path": "Whats-New-In-Swift-4-1.playground/Pages/Build configuration import testing.xcplaygroundpage/Contents.swift",
"chars": 1362,
"preview": "/*:\n [< Previous](@previous) [Home](Introduction) [Next >](@next)\n\n ## Build configuration import te"
},
{
"path": "Whats-New-In-Swift-4-1.playground/Pages/Conditional conformances.xcplaygroundpage/Contents.swift",
"chars": 3633,
"preview": "/*:\n [< Previous](@previous) [Home](Introduction) [Next >](@next)\n\n ## Conditional conformances\n\n Sw"
},
{
"path": "Whats-New-In-Swift-4-1.playground/Pages/Introduction.xcplaygroundpage/Contents.swift",
"chars": 1433,
"preview": "/*:\n # What’s new in Swift 4.1\n\n * Created by [Paul Hudson](https://twitter.com/twostraws) – [Hacking with Swift](https:"
},
{
"path": "Whats-New-In-Swift-4-1.playground/Pages/Key decoding strategy in Codable.xcplaygroundpage/Contents.swift",
"chars": 2830,
"preview": "/*:\n [< Previous](@previous) [Home](Introduction) [Next >](@next)\n\n ## Key decoding strategy in `Cod"
},
{
"path": "Whats-New-In-Swift-4-1.playground/Pages/Recursive constraints on associated types.xcplaygroundpage/Contents.swift",
"chars": 2515,
"preview": "/*:\n [< Previous](@previous) [Home](Introduction) [Next >](@next)\n\n ## Recursive constraints on asso"
},
{
"path": "Whats-New-In-Swift-4-1.playground/Pages/Synthesized Equatable and Hashable.xcplaygroundpage/Contents.swift",
"chars": 3374,
"preview": "/*:\n [< Previous](@previous) [Home](Introduction) [Next >](@next)\n\n ## Synthesized `Equatable` and `"
},
{
"path": "Whats-New-In-Swift-4-1.playground/Pages/Target environment testing.xcplaygroundpage/Contents.swift",
"chars": 2647,
"preview": "/*:\n [< Previous](@previous) [Home](Introduction) [Next >](@next)\n\n ## Target environment testing\n\n "
},
{
"path": "Whats-New-In-Swift-4-1.playground/Pages/flatMap() is now (partly) compactMap().xcplaygroundpage/Contents.swift",
"chars": 1083,
"preview": "/*:\n [< Previous](@previous) [Home](Introduction)\n\n ## `flatMap()` is now (partly) `compactMap()`\n\n The `flatM"
},
{
"path": "Whats-New-In-Swift-4-1.playground/contents.xcplayground",
"chars": 600,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<playground version='6.0' target-platform='ios' display-mode='re"
}
]
About this extraction
This page contains the full source code of the twostraws/whats-new-in-swift-4-1 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (21.8 KB), approximately 6.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.