Current Situation
A few weeks ago, SE-0328: Structural opaque result types was accepted with modification
As the quote, one of the modifications is relating to some
in parameter position. In this post, I'd like to share my thought about this point.
In the discussion of SE-0328, a conflict was found as a problem. Roughly speaking, it is the conflict between structural opaque result types and 'generalized some
syntax' which has been suggested for years.
// structural opaque result type
let closure: (some Numeric) -> () = { (value: Double) in print(value) }
// generalized some syntax (generics)
func function(value: some Numeric) { print(value) }
The behavior of closure
can be naturally inferred from the behaviors of other structural opaque result types. closure
and function
have the same type at a grance. However, their behaviors are exactly opposite; function
works as generic function.
The modification is that Swift forbids using, for example, (some Numeric) -> ()
for a while. But there seems no appropriate solution making both closure
and function
possible.
Simpler problem appears in the next example. How can one understand why the first some Numeric
is generic and the second some Numeric
is reverse generic? Generalized some
syntax has confusing problem from the beginning.
// generalized some syntax (generics) and opaque result type
func function(value: some Numeric) -> some Numeric { value }
It is not good to keep the situation as pending. The limitation of some
usage in parameter position is very artificial considering 'future direction' which most of Swift developers do not know. We should lift it as soon as possible.
Proposed Solution
Currently, we are trying to introduce three things:
- Structural opaque result types with
some
syntax (SE-0328) - Generalized
some
syntax (shorthand for generics) - Existential
any
syntax (explicit marker for exsitentials, SE-0335)
It was ideal that they are compatible with each other. However, 1 and 2 are making collision. There is no way to solve the problem rather than using a different marker. Since it is difficult to consider using some
for generics and not use for the whole structural opaque result types, generics should use other different marker.
- Structural opaque result types with
some
syntax - Generic
???
syntax (shorthand for generics) - Existential
any
syntax (explicit marker for existentials)
This is maybe the simplest and the most consistent solution. There are no artificial limitation and double meaning. With new marker, there is clearer distinction.
// closure and function behave equally
let closure: (some Numeric) -> () = { (value: Double) in print(value) }
func function(value: Double as some Numeric) { print(value) } // pseudo syntax
// closure and function behave equally
let closure: (??? Numeric) -> () = { print(value) }
func function<T: Numeric>(value: T) { print(value) }
func function(value: ??? Numeric) { print(value) }
// clear distinction between generics and reverse generics
func function(value: ??? Numeric) -> some Numeric { value }
// short hand for generic result types
func function() -> ??? Numeric { 42 }
There is room for bikeshedding about ???
marker. The marker should be carefully selected considering relationship among any
,some
, and ???
.
Summary
In summary, I suggested two points in this thread.
- Using
some
for generics causes conflict with structural opaque result types. It is better to usesome
exclusively for reverse generics. - For generics shorthand, other marker should be come up.
I strongly believe this is the almost only possible solution. I'd like to hear the evaluation of this solution, and what is appropriate for ???
marker. Any thoughts?