extension for Optional Task - swift

Can we make an extension of Optional type where wrapped type is async Task which is generic struct itself? I al so need to use Task underlying types inside.
Example of what I need (which is not working itself of course).
Need such parametrised extension, not just generic method inside clean Optional extension. Bottom example produces error "Cannot find type 'E' in scope".
extension Optional where Wrapped == Task<T, E> {
}
UPD:
I've tried to use the next solution but then I can't get the underlying type of wrapped Task to construct methods. It produces error: 'Success' is not a member type of type 'Wrapped'.
extension Optional where Wrapped == Task<Sendable, Error> {
func value(or operation: #escaping #Sendable () async -> Wrapped.Success) async throws {
let task: Task<Wrapped.Success, Wrapped.Failure>
}
}
UPD: More concrete example
extension Optional where Wrapped == Task<Sendable, Error> {
func value<Success: Sendable>(or operation: #escaping #Sendable () async throws -> Success) async throws -> Success {
let task: Task<Success, Error>
switch self {
case let .some(runningTask): task = runningTask //Cannot assign value of type 'Task<any Sendable, any Error>' to type 'Task<Success, any Error>'
case .none:
task = Task {
return try await operation()
}
}
return try await task.value
}
}

Extension where clauses cannot introduce new type parameters. This is just a current limitation of Swift syntax, and may be improved in the future. But it is always fixable by attaching the where clause to each method, which can introduce new type variables.
extension Optional {
func value<Success: Sendable>(or operation: #escaping #Sendable () async throws -> Success) async throws -> Success
where Wrapped == Task<Success, Error> // <===
{
...
}
}
If there are many methods with the same where clause this is slightly tedious, but it is always equivalent to putting it on the extension.

Related

Swift - protocol method signature based on associatedtype

Is it in Swift, like in TypeScript possible to define a struct where the methods depend on the generics?
protocol UseCase {
associatedtype Request
associatedtype Response
func execute(controller: () throws -> Request) async throws -> Response
}
If Request is Void, the protocol should return a different method signature.
func execute() async throws -> Response
I would write a protocol extension with where Request == Void:
extension UseCase where Request == Void {
func execute() async throws -> Response {
try await execute {}
}
}
When Request is Void, you can still call execute(controller:), but you can also call the parameterless execute().
When you conform to the protocol, you would need to implement execute(controller:), but this isn't a big problem, since you can just ignore the parameter.
Your contract would be a lie, violating the Liskov substitution principle. You can get around it with an underscore and a default parameter, but I recommend against it.
Also, I think you want Never, not Void—that's what Apple does.
struct JuiceCase: UseCase {
func execute(
controller _: () throws -> Never = { fatalError() }
) async throws -> String {
"🧃"
}
}
I'm trying to figure out what Cristik is saying in the comments but don't get it. What I see here is JuiceCase not semantically conforming to UseCase, even though it syntactically does. My interpretation of "substitutability" is that both must be correct—i.e. saying that JuiceCase is a UseCase is a lie, even though the compiler currently has no mechanism to verify that.
let juiceCase = JuiceCase()
try await juiceCase.execute() // "🧃"
let useCase: some UseCase = juiceCase
try await useCase.execute { fatalError() } // "🧃"

How to differentiate what generic value is what in Swift?

How can I differentiate what generic value is for what in Swift?
For example, what does the value 'T' do and what does the value 'E' do?
func ??<T, E>(result: Result<T, E>, handleError: (E) -> T) -> T {
switch result {
case let .success(value):
return value
case let .failure(error):
return handleError(error)
}
}
what does the value 'T' do and what does the value 'E' do?
They're not "values", they're the names of types — on a par with a term like String or Int. In fact, T could be String or Int. But E has to be some type of Error.
So the phrase <T, E>, which appears twice, just refers to the fact that T and E are generic placeholders for their real types. When someone actually calls this ?? function, the caller will make clear what T and E really are. This is called resolving the generic.
So let's imagine that we call ?? in such a way as to resolve T to String and E to Error. Then in the mind of the compiler, we'll have this:
func ??(result: Result<String, Error>, handleError: (Error) -> String) -> String {
switch result {
case let .success(value):
return value
case let .failure(error):
return handleError(error)
}
}
So now we can read the function declaration. It says: "You hand me two parameters. One, result:, must be a Result enum whose success type is String and whose failure type is Error. The other, handleError:, must be a function that takes an Error and returns a String. And I will return a String to you."
Except, of course, that that is only one way out of an infinite number of ways to resolve T and E. They stand in for the real types that will be resolved a compiled time, depending on how ?? is actually called. So there's your answer; that is "what they do". They are placeholders standing for the real types that will be resolved at compile time.
And in fact, to demonstrate, I will call your function in a way that resolves T to String and E to Error (though I will rename your function myFunc to make the name legal):
func myFunc<T, E>(result: Result<T, E>, handleError: (E) -> T) -> T {
switch result {
case let .success(value):
return value
case let .failure(error):
return handleError(error)
}
}
enum MyError : Error { case oops }
let r = Result<String, Error> { throw MyError.oops }
let output = myFunc(result:r) { err in "Ooops" }
print(output) // Ooops
Footnote: Note that your function cannot really be called ??, as that name is taken. It might have been better to call it foo (the usual nonsense name in these situations).
#matt's answer nails it, so I thought I'd add a like bit of higher level commentary.
Type parameter naming
The use of single characters for these generic type parameters is bit of a legacy a convention from Java and C#, but it need not be so concise. In this example, if you look at the main constraint on the types (Result), note that they use Success and Failure. Using these here would provide a clearer idea about the intent of this function:
func ??<Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success
Thus, a function that takes:
a Result that can either contain a Success or a Failure, and
a closure that takes a Failure and returns a Success
and returns:
a Success
Implementations bourne out of type system constraints
Note that as none of these types are wrapped in Optional the implementation of this function is almost entirely constrained (side-effects notwithstanding).
Take, for example, the simplest function that could seemingly match:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
return Success()
}
Attempting to compile this gives the following error:
main.swift:2:12: error: type 'Success' has no member 'init'
return Success()
^~~~~~~
due to the fact that the Success type is entirely unconstrained in Result, so we don't actually know how to create one inside the function.
We know that Result can contain a Success, so what if we try and forcibly get that?
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
return result.get()
}
This now fails with the following compiler error:
main.swift:2:12: error: call can throw, but it is not marked with 'try' and the error is not handled
return result.get()
^
due to the fact that this function has explicitly denoted that it will not throw, and Result.get() will throw the contained Failure if it does not contain a Success.
The other way to get the Success out of a Result is pattern matching, let's see how that works out matching the enumeration case pattern for a single if:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
if case let .success(success) = result {
return success
}
}
When attempting this, the compilation error is (quite sensibly):
main.swift:5:1: error: missing return in a function expected to return 'Success'
}
^
So we need to also handle the case when a Result contains a Failure. Let's try with another pattern match, using the provided handleError closure:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
if case let .success(success) = result {
return success
}
if case let .failure(failure) = result {
return handleError(failure)
}
}
This still gives the same error as the previous attempt, as the logic could still fall through in this case (this seems unlikely, but this could be subject to a kind of time-of-check to time-of-use bug).
Let's attempt it again, but matching both patterns in a switch:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
switch result {
case let .success(success):
return success
case let .failure(failure):
return handleError(failure)
}
}
There we go, compiling without error.
As is obvious, this is the original function, as provided in your question.
Now that we've arrived back here, can we trim down this implementation? We could try something like:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
switch result {
case let .success(success):
return success
}
}
but this provides this compilation error:
main.swift:2:5: error: switch must be exhaustive
switch result {
^
main.swift:2:5: note: add missing case: '.failure(_)'
switch result {
^
which indicates that we need that .failure(_) case to match all possible outcomes of the result.

How to fix cannot convert value of type Result<SuccessType<A>, Error> to closure result type Result<Success, Failure> Swift

I'm trying to map over Swift's Result type to produce a new Result of a different type but it isn't type checking, and is throwing the error:
error: cannot convert value of type Result<ParseSuccess<B>, ParseError> to closure result type Result<Success, Failure>
I've tried using a switch on the result and matching on the .success and .failure but I get a similar type checking error. I've also tried specifying the input and return types explicitly with no luck.
I've replicated the code in other languages I'm a little more familiar with (F# and Kotlin) and it seems to type check there.
The swift compiler shows a sqiggly under this line:
return self.apply(input).map { result in ParseSuccess(transform(result.data), result.input) }
Where am I going wrong with this code?
import Foundation
class ParseError : Error {
let err: String
init(_ err: String) {
self.err = err
}
}
class ParseSuccess<A> {
let data: A
let input: Substring
init(_ data: A, _ input: Substring) {
self.data = data
self.input = input
}
}
class Parser<A> {
let fn: (Substring) -> Result<ParseSuccess<A>, ParseError>
init(_ fn: #escaping (Substring) -> Result<ParseSuccess<A>, ParseError>) {
self.fn = fn
}
func apply(_ input: Substring) -> Result<ParseSuccess<A>, ParseError> {
return self.fn(input)
}
func map<B>(_ transform: #escaping (A) -> B) -> Parser<B> {
return Parser { (input) in
return self.apply(input).map { result in
ParseSuccess(transform(result.data), result.input) }
}
}
}
For what it's worth, I'm sure this is probably not the best way to start writing a parser combinator, but I've gotten caught up in trying to figure out where I went wrong here!
Thank you
It's a weird behaviour of the unqualified used of Paraser in the line return Parser {. When a generic type is mentioned in its unqualified form, within the body of the generic type's declaration, the type parameters are inferred to be unchanged. For example, a function on Array<T> can return simply Array, and the T is implied to be the same as the value of T for self. Needless to say, I'm not a huge fan of this behaviour.
Changing it to return Parser<B> { ... solves the issue.
Here's how I found the issue. When working with generics errors, I always try to insert a ton of type annotations to "pin down" the data types, to confirm that the compiler and me are on the same page.
I first wrote:
func map<B>(_ transform: #escaping (A) -> B) -> Parser<B> {
return Parser { (input) in
return self.apply(input).map { result in
let newData: ParseSuccess<B> = transform(result.data)
return ParseSuccess(newData, result.input)
}
}
}
At which point the error changed to:
Untitled 2.swift:32:10: error: cannot convert return expression of type 'Parser<A>' to return type 'Parser<B>'
return Parser { (input) in
^~~~~~~~~~~~~~~~~~~~

Swift inferring a completion handler closure to be the default #nonescaping instead of #escaping when completion handler explicitly uses #escaping

Swift 4.2, Xcode 10.1
In the order processing app I'm working on, the user may do a search for orders already processed or submitted. When that happens, it will check to see if it has a cache of orders, and if it does not, it will refill that cache using an asynchronous API request, then check the cache again.
The function that refills the cache is a private static one that accepts an escaping completion handler. Whenever I have used that completion handler in the past, all I had to do was add a closure at the end of the function call. This was before I was instructed to make a cache of all data wherever possible, and only use the API to refill that cache. Since then, the function has become private, because there will never be a need to call the API directly from anywhere but within this class.
Now, when I put the closure directly after the function call, it's giving me an error that basically says I'm passing a #nonescaping closure instead of an #escaping closure:
"Cannot invoke 'getAndCacheAPIData' with an argument list of type '(type: Codable.Type, (String?) -> Void)', Expected an argument list of type '(type: CodableClass.Type, #escaping (String?) -> Void)'"
I've never had to explicitly declare a closure to be #escaping before, nether does it seem to be possible. I suspect that because the function is both private AND static, there's some kind of issue happening with the way closures are inferred to be #escaping. I'm out of my depth. I could try converting the static class to a singleton, but I'm hesitant to refactor a bunch of working code because of one error until I'm absolutely sure that change will resolve the issue, and that what I'm trying to do isn't possible unless I change my approach.
Here's the code:
public static func fillSearchResultArray<ManagedClass: NSManagedObject>(query:String, parameters:[String], with type: ManagedClass.Type, completionHandler: #escaping (String?)->Void)
{
let codableType:Codable.Type
switch type
{
case is ClientTable.Type:
codableType = ClientData.self
case is OrderTable.Type:
codableType = OrderData.self
case is ProductTable.Type:
codableType = ProductData.self
default:
completionHandler("Unrecognized type.")
return
}
let fetchedData:[ManagedClass]
do
{
fetchedData = try PersistenceManager.shared.fetch(ManagedClass.self)
}
catch
{
completionHandler(error.localizedDescription)
return
}
if fetchedData.isEmpty
{
AppNetwork.getAndCacheAPIData(type: codableType)//error here
{(firstErrorString) in
//move search array data to the cache
if firstErrorString.exists
{
completionHandler(error)
}
else
{
AppNetwork.fillSearchResultArray(query: query, parameters: parameters, type: type)
{ errorString in
completionHandler(errorString)
}
}
}
return
}
else
{ ...
The signature of the function being called:
private static func getAndCacheAPIData <CodableClass: Any & Codable>(type:CodableClass.Type, completionHandler: #escaping (String?)->Void)
Why is swift inferring this closure to be the default #nonescaping when before it always inferred it to be #escaping?
The problem has nothing to do with the closure, or static, or private. It has to do with the type parameter. You cannot call this method:
private static func getAndCacheAPIData <CodableClass: Any & Codable>(type:CodableClass.Type, completionHandler: #escaping (String?)->Void)
with a variable of type Codable.Type. The type value you pass must be a concrete type, known at compile-time. If you want to pass a variable, you can't use a generic. It would have to be:
private static func getAndCacheAPIData(type: Codable.Type, completionHandler: #escaping (String?)->Void)
Alternately, you can call this as:
AppNetwork.getAndCacheAPIData(type: Int.self) {(firstErrorString) in ... }
or some other known-at-compile-time type.
Probably what you really want here is something like:
let completion: (String?) -> Void = {(firstErrorString) in ... }
switch ... {
case ...:
AppNetwork.getAndCacheAPIData(type: Int.self, completion: completion)
case ...:
AppNetwork.getAndCacheAPIData(type: String.self, completion: completion)
...
The basic problem is that protocols do not conform to themselves, so a variable of type Codable.Type does not satisfy the : Codable requirement. This comes down to the same reason you can't just call:
AppNetwork.getAndCacheAPIData(type: Codable.self) {...}
Alternately, you could refactor it this way:
private static func handleAPI<CodableClass: Codable>(type: CodableClass.Type) {
getAndCacheAPIData(type: type.self) { _ in ... the completion handler ..}
}
switch ... {
case ...:
AppNetwork.handleAPI(type: Int.self)
case ...:
AppNetwork.handleAPI(type: String.self)
...
Side note: Any & is meaningless here. You just meant <CodableClass: Codable>.

Swift optional escaping closure

Compiler error Closure use of non-escaping parameter 'completion' may allow it to escape, Which make sense because it will be called after the function return.
func sync(completion:(()->())) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion()
}
}
But if I make closure optional then no compiler error, Why is that? closure can still be called after the function returns.
func sync(completion:(()->())?) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion?()
}
}
Wrapping a closure in an Optional automatically marks it escaping. It's technically already "escaped" by being embedded into an enum (the Optional).
Clarification:
For understanding the case, implementing the following code would be useful:
typealias completion = () -> ()
enum CompletionHandler {
case success
case failure
static var handler: completion {
get { return { } }
set { }
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler.handler = handlerParameter
}
At the first look, this code seems to be legal, but it's not! you would get compile-time error complaining:
error: assigning non-escaping
parameter 'handlerParameter' to an #escaping closure
let chObject = CompletionHandler.handler = handlerParameter
with a note that:
note: parameter 'handlerParameter' is implicitly non-escaping func
doSomething(handlerParameter: completion) {
Why is that? the assumption is that the code snippet has nothing to do with the #escaping...
Actually, since Swift 3 has been released, the closure will be "escaped" if it's declared in enum, struct or class by default.
As a reference, there are bugs reported related to this issue:
Optional closure type is always considered #escaping.
#escaping failing on optional blocks.
Although they might not 100% related to this case, the assignee comments are clearly describe the case:
First comment:
The actual issue here is that optional closures are implicitly
#escaping right now.
Second comment:
That is unfortunately the case for Swift 3. Here are the semantics for
escaping in Swift 3:
1) Closures in function parameter position are
non-escaping by default
2) All other closures are escaping
Thus, all generic type argument closures, such as Array and Optional, are escaping.
Obviously, Optional is enum.
Also -as mentioned above-, the same behavior would be applicable for the classes and structs:
Class Case:
typealias completion = () -> ()
class CompletionHandler {
var handler: () -> ()
init(handler: () -> ()) {
self.handler = handler
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
Struct Case:
typealias completion = () -> ()
struct CompletionHandler {
var handler: completion
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
The two above code snippets would leads to the same output (compile-time error).
For fixing the case, you would need to let the function signature to be:
func doSomething( handlerParameter: #escaping completion)
Back to the Main Question:
Since you are expecting that you have to let the completion:(()->())? to be escaped, that would automatically done -as described above-.