If this would be a quick-fix I'd even suggest to make this first version of the 3 provided alternatives into
_ = Task {
let thing = try await someThing()
print(thing)
}
as it fits to the usual way we discard things that are not @discardableResult
and it's just 4 little characters of "boilerplate".
Logically, I second (or x-th) the idea that the Task
initializers should only be @discardable
when Success
== Void
and Failure
== Never
.
Small tangent & input about what's easier to grasp for a newbie (skip if you want):
I haven't run into this in production code (thankfully) yet, but while giving a quick, ill-prepared demo I gave to "advertise" for Swift's concurrency features. There's two issues at play here:
One is obviously the type inference combined with @discardableResult
. Developers new to Swift, and perhaps also to concurrency in general, are more likely to view Task
as a keyword and not an actual type whose values can be stored and used later. You do not get a "thing" that you can option-click to see what the compiler deduces for you in terms of type.
Instead it just looks like a special "scope notation", just like your first main
method or the top level in a playground. However, in a "normal scope" you get a compiler-note if you don't properly handle errors and it's not natural for somebody to deduce "ah, the compiler deduces a Task<Void, Error>
type here, then puts any errors in the discarded value of that type", so the error is actually handled, all the convenient "implicitness" of it just hides it. That's only apparent for somebody who's already intricately familiar with Swift.
We may have become a little "operationally blind" to the fact that no matter how well we design the language and what tools we provide, concurrency is hard. Yes, requiring a more explicit discarding of errors adds "boilerplate" for all those who just know that errors inside a simple Task { ... }
can be swallowed and if they are actually interested in the error they will catch
or await
it somehow, but I think that strides to far from Swift's safe-ness philosophy. With quick-fixes and a minimal _ =
in front of those Task
s we'd fare much better, I think.
For me Swift has been an excellent tool not just to learn about more advanced stuff myself, but also to teach concepts such as concurrency (another would be value- vs reference-semantics). Every time I need to explain "ah, this is a non-obvious special case where these 5 things play together" it loses a little of teachability, though.