What’s new in Swift 6.1? – Donny Wals

What’s new in Swift 6.1? – Donny Wals


The Xcode 16.3 beta is out, which features a new model of Swift. Swift 6.1 is a comparatively small launch that comes with bug fixes, high quality of life enhancements, and a few options. On this publish, I’d prefer to discover two of the brand new options that include Swift 6.1. One that you would be able to begin utilizing instantly, and one that you would be able to opt-in on if it is smart for you.

The options I’d prefer to discover are the next:

  1. Adjustments to Activity Teams in Swift 6.1
  2. Adjustments to member visibility for imported code

We’ll begin by wanting on the modifications in Concurrency’s TaskGroup and we’ll cowl member visibility after.

Swift 6.1 and TaskGroup

There have been a few modifications to concurrency in Swift 6.1. These have been primarily small bug fixes and enhancements however one enchancment stood out to me and that’s the modifications which are made to TaskGroup. If you happen to’re not aware of process teams, go forward and skim up on them on my weblog publish proper right here.

Usually, a TaskGroup is created as proven beneath the place we create a process group and specify the kind of worth that each youngster process goes to provide:

await withTaskGroup(of: Int.self) { group in
  for _ in 1...10 {
    group.addTask {
      return Int.random(in: 1...10)
    }
  }
}

Beginning in Swift 6.1, Apple has made it in order that we not must explicitly outline the return kind for our youngster duties. As a substitute, Swift can infer the return kind of kid duties primarily based on the primary process that we add to the group.

That implies that the compiler will useaddGroup it finds to find out the return kind for all of your youngster duties.

In observe, that implies that the code beneath is the equal of what we noticed earlier:

await withTaskGroup { group in
  for _ in 1...10 {
    group.addTask {
      return Int.random(in: 1...10)
    }
  }
}

Now, as you would possibly anticipate, this does not change the truth that our process teams must return the identical kind for each youngster process.

The code above reveals you ways you need to use this new return kind inference in Swift 6.1. If you happen to unintentionally do find yourself with completely different return sorts in your youngster process just like the code beneath reveals, the compiler will current us with an error that can inform you that the return kind of your name to addTask is wrong.

await withTaskGroup { group in
  for _ in 1...10 {
    group.addTask {
      return Int.random(in: 1...10)
    }
  }

  group.addTask {
    // Can't convert worth of kind 'String' to closure end result kind 'Int'
    return "Hey, world"
  }
}

Now, should you discover that you just do wish to have a number of return sorts, I’ve a weblog publish on that. That method nonetheless works. We will nonetheless use an enum as a return kind for our process group for our youngster duties, and that positively nonetheless is a legitimate strategy to have a number of return sorts in a process group.

I’m fairly proud of this modification as a result of having to specify the return kind for my youngster duties at all times felt somewhat tedious so it’s nice to see the compiler take this job in Swift 6.1.

Subsequent, let’s check out the modifications to imported member visibility in Swift 6.1.

Imported member visibility in Swift 6.1

In Swift, we now have the flexibility so as to add extensions to sorts to boost or increase performance that we have already got. For instance, you may add an extension to an Int to signify it as a forex string or one thing comparable.

If I am constructing an app the place I am coping with currencies and purchases and dealing with cash, I may need two packages which are imported by my app. Each packages might be coping with currencies in a roundabout way form or type and I may need an extension on Int that returns a String which is a forex string as I discussed earlier.

This is what that would appear like.

// CurrencyKit
func value() -> String {
    let formatter = NumberFormatter()
    formatter.numberStyle = .forex
    formatter.locale = Locale.present

    let quantity = Double(self) / 100.0 // Assuming the integer represents cents
    return formatter.string(from: NSNumber(worth: quantity)) ?? "$(quantity)"
}

// PurchaseParser
func value() -> String {
    let formatter = NumberFormatter()
    formatter.numberStyle = .forex
    formatter.locale = Locale.present

    let quantity = Double(self) / 100.0 // Assuming the integer represents cents
    return formatter.string(from: NSNumber(worth: quantity)) ?? "$(quantity)"
}

The extension proven above exists in each of my packages, and the return forms of these extensions are the very same (i.e., strings). Because of this I can have the next two information in my app, and it is going to be simply superb.

// FileOne.swift
import PurchaseParser

func dealsWithPurchase() {
    let quantity = 1000
    let purchaseString = quantity.value()
    print(purchaseString)
}

// FileTwo.swift
import CurrencyKit

func dealsWithCurrency() {
    let quantity = 1000
    let currencyString = quantity.value()
    print(currencyString)
}

The compiler will understand how to determine which model of value ought to be used primarily based on the import in my information and issues will work simply superb.

Nonetheless, if I’ve two extensions on integer with the identical perform identify however completely different return sorts, the compiler would possibly really get confused about which model of the extension I meant to make use of.

Take into account the next modifications to PurchaseParser‘s value methodology:

func value() -> Double {
    let formatter = NumberFormatter()
    formatter.numberStyle = .forex
    formatter.locale = Locale.present

    let quantity = Double(self) / 100.0 // Assuming the integer represents cents
    return quantity
}

Now, value returns a Double as a substitute of a String. In my app code, I’m able to use this extension from any file, even when that file doesn’t explicitly import PurchaseParser. In consequence, the compiler isn’t certain what I imply once I write the next code in both of the 2 information that you just noticed earlier:

let quantity = 1000
let currencyString = quantity.value()

Am I anticipating currencyString to be a String or am I anticipating it to be a Double?

To assist the compiler, I can explicitly kind currencyString as follows:

let quantity = 1000
let currencyString: String = quantity.value()

It will inform the compiler which model of value ought to be used, and my code will work once more. Nonetheless, it’s form of unusual in a method that the compiler is utilizing an extension on Int that’s outlined in a module that I didn’t even import on this particular file.

In Swift 6.1, we are able to choose into a brand new member visibility mode. This member visibility mode goes to work somewhat bit extra such as you would possibly anticipate.

Once I import a selected module like CurrencyKit, I am solely going to be utilizing extensions that have been outlined on CurrencyKit. Because of this in a file that solely imports CurrencyKit I gained’t be capable to use extensions outlined in different packages until I additionally import these. In consequence, the compiler gained’t be confused about having a number of extensions with the tactic identify anymore since it may well’t see what I don’t import.

Opting into this function will be executed by passing the corresponding function flag to your package deal, this is what that appears like while you’re in a Swift package deal:

.executableTarget(
    identify: "AppTarget",
    dependencies: [
        "CurrencyKit",
        "PurchaseParser"
    ],
    swiftSettings: [
        .enableExperimentalFeature("MemberImportVisibility")
    ]
),

In Xcode this may be executed by passing the function to the “Different Swift Flags” setting in your mission settings. In this publish I clarify precisely how to do this.

Whereas I completely love this function, and I believe it is a actually good change in Swift, it doesn’t clear up an issue that I’ve had often. Nonetheless, I can positively think about myself having that drawback, so I am glad that there is now a repair for that that we are able to choose into. Hopefully, it will ultimately grow to be a default in Swift.

In Abstract

Total, Swift 6.1 is a reasonably light-weight launch, and it has some good enhancements that I believe actually assist the language be higher than it was earlier than.

What are your ideas on these modifications in Swift 6.1, and do you assume that they’ll influence your work in any method in any respect?

Leave a Reply

Your email address will not be published. Required fields are marked *