Identifying child tasks within a TaskGroup

a lot of times i have “multifaceted” task groups that look like:

try await withThrowingTaskGroup(of: Void.self)
{
    (tasks:inout ThrowingTaskGroup<Void, any Error>) in

    tasks.addTask
    {
        try await self.runA()
    }
    tasks.addTask
    {
        try await self.runB()
    }
    tasks.addTask
    {
        try await self.runC()
    }

    for try await _:Void in tasks
    {
        tasks.cancelAll()
    }
}

but then i want to know which task died first, which isn’t exactly straightforward because we need to give the child tasks names and attach their names to both the return value and the thrown any Error.

can we do better?

Would this work?

enum TaskName {
  case a, b, c
}

func getError(body: () async throws -> Void) async -> Error? {
  do {
    try await body()
    return nil
  } catch {
    return error
  }
}

try await withTaskGroup(of: (TaskName, Error?).self) { tasks in
  tasks.addTask {
    await (.a, getError(self.runA))
  }

  tasks.addTask {
    await (.b, getError(self.runB))
  }

  tasks.addTask {
    await (.c, getError(self.runC))
  }

  for await firstCompletion in tasks {
    tasks.cancelAll()
    return firstCompletion
  }
  fatalError("unreachable")
}