Fixing “Job-isolated worth of sort ‘() async -> Void’ handed as a strongly transferred parameter”


Revealed on: August 21, 2024

When you begin migrating to the Swift 6 language mode, you will most certainly activate strict concurrency first. As soon as you have finished this there can be a number of warings and errors that you’re going to encounter and these errors might be complicated at occasions.

I am going to begin by saying that having a stable understanding of actors, sendable, and information races is a big benefit while you wish to undertake the Swift 6 language mode. Just about all the warnings you will get in strict concurrency mode will let you know about potential points associated to working code concurrently. For an in-depth understanding of actors, sendability and information races I extremely advocate that you just check out my Swift Concurrency course which can get you entry to a sequence of movies, workouts, and my Sensible Swift Concurrency ebook with a single buy.

WIth that out of the way in which, let’s check out the next warning that you just may encounter in your venture:

Job-isolated worth of sort ‘() async -> Void’ handed as a strongly transferred parameter

After I first encountered the error above, I used to be puzzled. The code that made this occur wasn’t all that unusual and I had no concept what may very well be improper right here.

Let us take a look at an instance of the code that may make this error present up:

var myArray = [1, 2, 3]

await withTaskGroup(of: Void.self) { group in
  for _ in 0..<10 {
    // Job-isolated worth of sort '() async -> Void' handed as a strongly transferred parameter; later accesses may race;
    group.addTask { 
      myArray.append(Int.random(in: 0..<10))
    }
  }
}

The issue above may also happen while you create an unstructured activity with Job or a indifferent activity with Job.indifferent. The error and the rationale for the error showing are the identical for all instances, however what precisely is improper within the code above?

Sadly, the compiler is not of a lot assist right here so we’ll must determine this one out on our personal…

In each case that I’ve seen for this particular error, the duty that we create (whether or not it is a youngster activity, unstructured activity or a indifferent activity) captures a non-sendable object. To study extra about sendable, check out my put up that explains Sendable and @Sendable closures.

So whereas the compiler error is extraordinarily laborious to learn and perceive, the rationale for it showing is definitely comparatively easy. We have a robust seize to one thing that is not Sendable within a activity which may run concurrently with different work. The result’s a potential information race.

The repair can generally be comparatively easy in the event you’re capable of make the captured sort sendable or an actor. Within the case of the code above that may be tough; myArray is an array of Int which implies that we’re already as sendable as we may very well be. However as a result of the array is mutable, there’s an opportunity that we’ll race.

There are a number of potential fixes on this case. Considered one of them is to mutate the array exterior of the kid duties by having youngster duties produce numbers after which iterating over the duty group:

var myArray = [1, 2, 3]

await withTaskGroup(of: Int.self) { group in
  for _ in 0..<10 {
      group.addTask {
          // Job-isolated worth of sort '() async -> Void' handed as a strongly transferred parameter; later accesses may race;
          return (myArray.first ?? 2) * 2
      }
  }

    for await worth in group {
        myArray.append(worth)
    }
}

Sadly, the above nonetheless produces an error…

The rationale for that’s that myArray continues to be being accessed from inside a baby activity. In order that implies that whereas a baby activity is studying, our async for loop may very well be writing after which we’ve an information race.

To repair that we have to make a replica of myArray within the youngster activity’s seize listing like this:

group.addTask { [myArray] in
  return (myArray.first ?? 2) * 2
}

With that change in place, the code compiles and runs appropriately.

Sadly, Job-isolated worth of sort '() async -> Void' handed as a strongly transferred parameter is a really powerful to learn error with no single repair. What this error tells you although, is that you just’re accessing or capturing a price that is not sendable or protected to be accessed concurrently. Fixes for this may very well be:

  1. To make the captured object an actor
  2. To make the captured object sendable
  3. To make a replica of the thing
  4. To seize properties on the thing exterior of your activity
  5. To rethink your method fully (that is not often wanted)

As with many different strict concurrency associated points, fixing this error will rely in your skill to research the issue, and your understanding of actors and sendable. These are matters that you need to attempt to perceive nearly as good as you possibly can earlier than you try and migrate to Swift 6.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles