Rethrows is converted to throws mistakenly

We know that the signature of the map method of Array<Element> is:

func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]

However the type of ( where somArray: [Element]) is:

((Element) throws -> T) throws -> [T]

instead of:

((Element) throws -> T) rethrows -> [T]

which makes me confused.

Could you show how you observe that type?

The quoted snippet does not compile for me.

The problem is that closures do not support rethrows. E.g. if you try to write this:

typealias ClosureWithRethrows = (() throws -> Void) rethrows -> Void

The compiler will complain with the error message: Only function declarations may be marked 'rethrows'; did you mean 'throws'?

Besides that, I can't really say much about unapplied method references because I haven't really found a use case for them and therefore don't have much experience with them. Anything particular you want to accomplish?

BTW: closures do not support generics either.


Unapplied method references were severely damaged by Swifts early attempts to support currying. They work, awkwardly, for regular methods, but they break as soon as you try to apply them to mutating methods. Unless fixing them is on the table for Swift 6, I believe they're largely being ignored in favor of keypaths.

Which is a shame because a proposal to fix them had been accepted, but never got implemented in time.

The general closure issues probably have a better chance of being fixed, but it would require someone to write an implementation.


rethrows is a property of the declaration, not of the function type, so only an application of a direct declaration reference can be rethrows, and not an application of an arbitrary value. Argument labels, default arguments and generics are similarly not part of a function type and only come into play when you're applying a direct declaration reference.


As an aside, this is a major feature and it is not at all clear that we want it for Swift, both in terms of the opportunity cost because we could spend the time working on other issues, but also the inherent complexity it adds to the type system: Rank-N types - HaskellWiki


Whenever you declare a function with rethrows, you're essentially declaring two separate functions. For example:

func call(_ body: () throws -> Int) rethrows -> Int { try body() }

is equivalent to

func call(_ body: () -> Int) -> Int { body() }
func call(_ body: () throws -> Int) throws -> Int { try body() }

Because these are two functions, you can't have a single function instance that represents them both.

When you use a function's name to create a function instance, the compiler chooses to use the throwing version of the function instead of the non-throwing one. To use the non-throwing version of the function, you'll have to use a closure.

let function = { (body: () -> Int) in call(body) }

(It may be useful if a feature were added to the language such that let function: (() -> Int) -> Int = call would be a valid way to access the non-throwing function. Alas, this feature does not yet exist.)

1 Like

It seems pretty obvious you could, if Swift could track effects as part of function references. I haven't seen anything so far that says that's impossible, just that Swift doesn't do it yet, and that it may be undesirable in some circumstances.

1 Like