I generally agree, of course the devil is in the details, isn't it!
I thought we were going to need to decide this before a
Result proposal would make it to review, but here we are. I actually think that's ok. I am also fine with making the decision now as long as it is decided in favor of #2.
I would strongly oppose a
Result that did not allow for typed errors. That removes flexibility that is occasionally extremely useful. I would prefer to not have
Result in the standard library if it were limited to the untyped variant. The typed design allows people to simply use
Result<T, Swift.Error> to recover the behavior of an untyped result (and even introduce a typealias if desired). The untyped design forces those of us who find typed errors useful to fight the language one way or another. The current state of choosing third party libraries or rolling our own is much better than having to fight the language.
This was discussed extensively in the pitch thread. I wish you would have participated there!
throws to transforms on
Result is categorically different than it is on other types, such as collections and optional. The version of
map you advocate for is a syntactic transformation of
flatMap semantics. I think it's important that the name reflect the semantics of the operation. Using
map here does not feel right to me.
Further, in Swift 5 (where this would be accepted) your
map only works when
Error == Swift.Error but surely we want
map to be included without constraints. Your version of
map could be included in a constrained extension along side an unconstrained non-throwing
map. That would be a simple renaming of the throwing
flatMap in the proposal.
Of course this would be subject to the concern @John_McCall brought up a concern regarding overloading only on whether the transform throws or not. I am unsure how often problems would arise in practice - people are unlikely to want to return
Result from the throwing overload and must return
Result from the non-throwing overload. However, the bar for acceptance in the standard library should be very high and the potential for problems with this overload is certainly present. I now believe throwing transforms should not be included if the proposal is accepted.
I don't believe there are good alternative names for the methods with throwing transforms. People could bikeshed if desired, but very much doubt anything remotely resembling consensus would emerge. It is trivial for those who want them to add them in extensions. If substantial experience proves that the overload is not a problem perhaps they could be proposed down the road.
Assuming we did have typed throws, the type signatures you proposed would perhaps make good replacements for
flatMapError methods in the proposal. However, the names should remain the same. The semantics of flattening remain and are distinct from a simple
This issue is significant in the case of your
mapError which returns
Value rather than a new error type. When users actually just want to map the error they would be forced to provide a function which always throws. That is rather unusual and certainly unprecedented in the standard library.
I see no good argument for this whatsoever. This introduces jargon for jargon's sake. Swift programmers are becoming quite familiar with
map and it's variants -
Foo selects part(s) of an aggregate).
This change happened for good reason - the method now named
compactMap was never semantically a
flatMap and that caused plenty of confusion. Another name that was considered for this operation is
filterMap which expresses the semantics of the operation rather clearly - it is single operation that both maps and filters, just as flat map is an operation that both maps and flattens. We definitely should not introduce new names for an operation that is semantically equivalent to a
I strongly oppose including an initializer like this. The use case is common enough but there simply is not a design that is obvious enough to warrant inclusion in the standard library. It is impossible to know a-priori how to handle the two
nil case, and especially the value and error case. If this initializer is included in the standard library people will use it whether or not it is appropriate for a specific use case.