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

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


Printed on: August 21, 2024

When you begin migrating to the Swift 6 language mode, you may more than likely activate strict concurrency first. As soon as you’ve got accomplished this there might be a number of warings and errors that you’re going to encounter and these errors may be complicated at instances.

I am going to begin by saying that having a stable understanding of actors, sendable, and information races is a big benefit whenever you need to undertake the Swift 6 language mode. Just about the entire warnings you may 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 guide with a single buy.

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

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 thought what might be flawed right here.

Let us take a look at an instance of the code that might 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 might race;
    group.addTask { 
      myArray.append(Int.random(in: 0..<10))
    }
  }
}

The issue above can even happen whenever 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 circumstances, however what precisely is flawed 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 exhausting 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 that may run concurrently with different work. The result’s a attainable information race.

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

There are a number of attainable fixes on this case. Certainly 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 might race;
          return (myArray.first ?? 2) * 2
      }
  }

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

Sadly, the above nonetheless produces an error…

The explanation for that’s that myArray remains to be being accessed from inside a toddler activity. In order that implies that whereas a toddler activity is studying, our async for loop might be writing after which we now have an information race.

To repair that we have to make a duplicate 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 accurately.

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 worth that is not sendable or secure to be accessed concurrently. Fixes for this might be:

  1. To make the captured object an actor
  2. To make the captured object sendable
  3. To make a duplicate of the article
  4. To seize properties on the article exterior of your activity
  5. To rethink your method fully (that is hardly ever wanted)

As with many different strict concurrency associated points, fixing this error will rely in your capability to research the issue, and your understanding of actors and sendable. These are subjects that it’s best to attempt to perceive pretty much as good as you may earlier than you try and migrate to Swift 6.

Leave a Reply

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