Gaps in primary associated type support?

Hi,

In the detailed design section of SE-0346 - Lightweight same-type requirements for primary associated types, it demonstrates a function which returns an opaque Collection of opaque Equatable elements:

Constrained protocols in opaque result types

  • A constrained protocol may appear in an opaque result type specified by the some keyword. In this case, the syntax actually allows you to express something that was previously not possible to write, since we do not allow where clauses on opaque result types:
func transformElements<S : Sequence<E>, E>(_ lines: S) -> some Sequence<E>

This example also demonstrates that the argument can itself depend on generic parameters from the outer scope. The SE-0328 Structural Opaque Result Types pitch allows multiple occurrences of some in a return type. This generalizes to constrained protocol types, whose constraint can be another opaque result type:

func transform(_: some Sequence<some Equatable>) -> some Sequence<some Equatable>

Note that in the above, the opaque result type some Sequence<some Equatable> is unrelated to the opaque parameter type some Sequence<some Equatable>. The parameter type is provided by the caller. The opaque result type is a (possibly different) homogeneous sequence of elements, where the element type is known to conform to some Equatable but is otherwise opaque to the caller.

This second function doesn't compile. In fact I've found that opaque return types in general don't support other opaque types as primary associated types:

// Both errors
// 'some' types are only permitted in properties, subscripts, and functions

func foo() -> some Collection<some Equatable> {
  [1]
}

var x: some Collection<some Equatable> {
  [1]
}

It's weird because using opaque types in this way (as constraints) works if the outer type is concrete:

// Works

func foo() -> Array<some Equatable> {
  [1]
}

var x: Array<some Equatable> {
  [1]
}

The one place this construct does seem to be allowed is in parameter position, as a shorthand for generics (this example is also from SE-0346):

// Works! But nowhere else :S

func sort(elements: inout some Collection<some Equatable>) {}

Is this gap known about? The way it is described in the proposal, it seems like the intention was for this to support opaque return types. Are there implementation issues blocking it, or could it be an oversight?

9 Likes

I think this is a known issue: swiftlang/swift#61409.

6 Likes

not trying to snark, why do basic gaps like this sit as bugs for years while new features keep getting proposed?

5 Likes

When prioritizing work and allocating resources, sometimes new features can act as a significantly larger multiplier for improving the language/unblocking others/accelerating other work than certain bug fixes, and make sense to prioritize. There's always more to do and improve than time to do it, and trying to find the balance between time spent and impact made is challenging. (Edit: to clarify: for this reason, Swift has several working groups that focus on a variety of areas in developing the language; groups can, in parallel, propose and work on new language features and APIs, while others prioritize other work. These are not mutually exclusive.)

I do think it's fair to ask "if this was highlighted as possible in the proposal, why did it not land as part of the main implementation, or why was the proposal not amended to reflect this change?", i.e., as Karl has, but this doesn't need to be a blocker for all future work.

For the record, another SE-0346 feature that was not implemented is described at Shorthand conformance to a protocol with a primary associated type