How to write @Sendable function composition by parameter packs and function overloading?

The compiler will complain about ambiguous function calls if I provide @Sendable function composition and the non-sendable version at the same time.

Do I really have to provide the compose function with difference names, e.g. sendableCompose, unsendableCompose?

@Sendable
public func compose <each A, B, C>(
    _ g: @escaping @Sendable (B) -> C,
    _ f: @escaping @Sendable (repeat each A) -> B
) -> (repeat each A) -> C {
    { (args: repeat each A) in
        g(f(repeat each args))
    }
}


public func compose <each A, B, C>(
    _ g: @escaping  (B) -> C,
    _ f: @escaping  (repeat each A) -> B
) -> (repeat each A) -> C {
    { (args: repeat each A) in
        g(f(repeat each args))
    }
}
2 Likes

It should be


public func compose <each A, B, C>(
    _ g: @escaping @Sendable (B) -> C,
    _ f: @escaping @Sendable (repeat each A) -> B
) -> @Sendable (repeat each A) -> C {
    { (args: repeat each A) in
        g(f(repeat each args))
    }
}


public func compose <each A, B, C>(
    _ g: @escaping  (B) -> C,
    _ f: @escaping  (repeat each A) -> B
) -> (repeat each A) -> C {
    { (args: repeat each A) in
        g(f(repeat each args))
    }
}

The leading @Sendable is unnecessary in Swift 6.0 (see SE-0418 )

The return value needs @Sendable.

1 Like

You can disambiguate with explicit Sendable. But how do you explicitly remove Sendable?

func f() {
  @Sendable func f(_: Never, _: Never) -> Never {  }
  _ = compose(\.self, f) as @Sendable (_, _) -> _ // Compiles
  _ = compose(\.self, nonSendable(f))             // Compiles
  _ = compose(\.self, f)                          // Ambiguous use of 'compose'
}

You can get typed errors compiling with this signature, but the compiler crashes if you try to actually use that.

public func nonSendable<each Input, Value>(
  _ closure: @escaping @Sendable (repeat each Input) -> Value
) -> (repeat each Input) -> Value {
  closure
}