SE-0244: Opaque Result Types (reopened)

(Johannes Weiss) #12

+1!

  • What is your evaluation of the proposal?

Great!

  • Is the problem being addressed significant enough to warrant a change to Swift?

Definitely, long-standing problem that is now being addressed without penalising performance. In SwiftNIO we don’t expose the concrete Channel (ServerSocketChannel vs SocketChannel etc) types to you and they’re existentials right now which is not optimal (but we get away with it).

  • Does this proposal fit well with the feel and direction of Swift?

Absolutely

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

No

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the first version in depth, this some slightly less so but seems to be mostly the same :slight_smile:

(Cory Benfield) #13

Before I go further, a minor nit:

The second paragraph in the "Proposed Solution" section contains an error. Specifically, it contains the following (grammatically invalid) sentence: "Unlike an existential, though, clients still have access to the type identity, so values This allows the library to provide a potentially-more-efficient design that leverages Swift's type system, without expanding the surface area of the library or making implementors of the library's protocols rely on exposing verbose implementation types.".

It seems that this was intended to be two sentences, and the first one was truncated which caused the period to be missed as well. For the benefit of future us looking backwards it'd be nice if @Joe_Groff could add the missing sentence back!

Along with @johannesweiss I am an enthusiastic +1. I have been thinking of attempting to add more expressiveness to SwiftNIO's current Bootstrap abstractions, but this expressiveness has been limited by the fact that we extensively use Channel as an existential container to hide the concrete type, which prevents us providing associatedtypes on the Channel protocol. This change would lift that restriction and make it easier for us to allow users to program generically over both Channels and Bootstraps.

Yes. The proposal makes it clear that in addition to providing a helpful tool for libraries like SwiftNIO, it is reasonable to think of Opaque Result Types as a currently-absent dual of caller-selected generics. Adding this missing symmetry to the language is a good thing.

I believe so. The specific spellings proposed in this pitch are novel, but there is a clear roadmap for how they will evolve, and the place we'd end up seems reasonably in keeping with Swift.

N/A

In-depth reading of both the original proposal and this one, as well as the follow-up threads.

1 Like
(Joe Groff) #14

Thanks for reporting the typo! I'll fix that.

1 Like
(Matt Seaman) #15

Giant +1. This would be major step towards alleviating my largest battle with the Swift type system.

Yes. As stated above, the restriction on not being able to use protocols with associated types and Self requirements in regular type locations is the biggest pain point for me when implementing complex systems. While this proposal does not completely solve that issue, it goes a long way for the most common instances.

Yes. "some" reads like English and expresses the intent clearly. Seems like a natural extension to Swift.

N/A

I read the Generics UI document, the proposal, and reviewed the existing reviews. I am also familiar with the Generics Manifesto.

(Alejandro Martinez) #16

I'm in favour of this change. I think that mitigating the complexity of the return types any time you write some code around Collections is a needed improvement to the language.

Yes. I've read the previous thread and found the commentary about opaque typealias worth considering, but honestly, I think that the major impact that this proposal would have on existing "application" will be to reduce the noise around Collection types. And for that scenario typealiases don't improve anything. I'm happy to get this as is and improve the support with typelias if needed in the future.

I think so, it fills an important gap on the language. On the original thread I was more in favour of opaque but seeing the future of the generics system this makes sense.

Hiding the concrete implementation of something is quite common in some libraries and other languages, things like "tokens".

Followed the topic since the original discussion, read those threads and the new post about generics.

(Brent Royal-Gordon) #17

In the previous review thread, I said:

I'm in favor of the feature and I think the proposal covers enough ground to be a useful addition to the language.

However, the vague syntax suggestions in the "Future Directions" section concern me. I'm worried that the -> some P syntax may be adequate for this proposal's purposes, but may not extend cleanly to uses we envision in the future. Maybe there is some larger scheme we could fit the some syntax into; if so, I'd like to see a sketch of that scheme before we commit to it here. (More thoughts on that in the Protocol<.AssocType == T> thread.)

Otherwise, I support it.

The "generics UI manifesto" has addressed my future-directions-related concerns and I support its overall vision. I also still support the feature itself.

I'm a little hesitant about the decision to introduce the some syntax with this proposal and defer the full "reverse generics" syntax for later, but I ultimately think it's the right decision. Once we support (...) -> <T: P> T syntax, people will immediately try to use it in ways the current implementation doesn't support. It would be a poor experience for users to have so many different things be straightforward to express but unsupported, and I don't think it makes sense to delay opaque result types until they can support every bell and whistle the generics system has to offer. Therefore, shipping opaque result types with only the some syntax is our best option.

I look forward to seeing some of the other results of the generics UI manifesto. some in parameter position seems like especially juicy and low-hanging fruit—I've had to explain to several different people why inout P parameters don't do what they want, and inout some P would be a very nice solution to offer them.

1 Like
#18

Strong +1. I don't have any strong feelings on the specific syntax being proposed, so I'll leave arguing over that to other folks, but I'm very much in favor of the spirit of this pitch.

Yes absolutely.

I believe so. I'm a heavy user of Swift's generics and this feature would resolve a good portion of the issues I face. The other features listed in the Generics UI post would solve most of the rest.

I haven't

I read the generics manifesto, generics UI post, proposal, diff, most of the associated threads.

(Pitiphong Phongpattranont) #19

What is your evaluation of the proposal?
I would give this it a YES

Is the problem being addressed significant enough to warrant a change to Swift?
As a developer who develops and maintains a few libraries, I would say YES
Does this proposal fit well with the feel and direction of Swift?
I believe it does

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
[N/A]

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
I would like to try a try since it looks promising. However I couldn't load the toolchain linked in the Swift Evolution. Where can I get a toolchain to try this? I have a few questions but did found answers to those question in both the a reading in the SE and read through the old proposal thread.

(Jens Ayton) #20

The new manifesto makes it much clearer where this fits and and why it’s not an edge case with way too much conceptual overhead, which is how it looked before. I do think there will be a pedagogical problem, but it no longer looks insurmountable.

I’m a little bit worried that the lack of composability, especially the inability to use Optional<some T>, will be a sharp edge.

3 Likes
(Mox) #21

As was mentioned in Improving the UI of generics thread, I'd much prefer using syntax of

func makeAnimals() -> (some Animal T, some Animal U) { ... }

for naming the types, applying to both some and any types. And in both parameter and return type positions.

3 Likes
(Mox) #22

Overall +1 on the Opaque Result Types proposal. I truly appreciate the "MVP" nature of this proposal. Not trying to cram in too much in the first round of this feature. Well done!

Improving the UI of generics
#24

I'm guessing you didn't read any of the follow-up posts, nor the revised proposal. A method for resolving this difficulty is explicitly mentioned as a future direction. It does no good to make a snarky comment that contains a blatantly untrue statement.

2 Likes
(Ben Cohen) #25

Please keep your comments constructive. You are welcome to criticize the proposal for the reasons you give, but the tone needs to be consistent with the code of conduct. This means not attacking the authors of proposals, and not using hyperbolic (and politically charged) analogies.

11 Likes
#26

As long as that difficulty isn't resolved, the proposal isn't useful at all. So having it in "future directions" wouldn't be enough.

Also, I don't see anything in "future directions" that would actually resolve it, do you mind pointing me towards what you were talking about?

#27

Sure, silence me if you need to, but everybody that takes an actual look at this will see that in terms of what would happen if this proposal would be accepted, the only difference is that they replaced the opaque keyword with some. It's exactly the same otherwise. Exactly as bad as it used to be.

#28

One of the future directions (at the very bottom of the proposal) is introducing any as a dual to some for explicitly spelling existential types.

Unless I am mistaken about the proposal (which I may well be), this would allow you to write something like

let d: [any A] = [b(), c()]
#29

But any would be an existential type. If I need existential types to use my opaque types properly, then opaque types aren't useful alone. And if that's the case – if I'm going to end up using existentials anyways eventually in the code – why not just use existentials to begin with?

func b() -> any A {
    return ...
}
#30

That's a pretty large generalization; opaque types are useful "alone" (without existential types), as the proposal demonstrates with many different use-cases. If you closely read the proposal, you will find that some is actually intended to be implemented as syntactic sugar for "reverse generics," as they are referred to in the proposal. Using some is not the same thing as using an existential type.

3 Likes
(Jon Hull) #31

There are some holes, but I still think the feature is useful by itself. The important thing is that there is a path to eventually allow arrays and optionals of these types in the future.

We definitely should double check that we aren't painting ourselves into a corner...

I would personally like to see the ability to define one of these Opaque types in a typealias to be used within the entire type, and it would be known to be the same type throughout the type. Not sure how hard that would be on the type checker though.

If it was possible, it would also eventually allow these opaque types to be passed in parameters, which would open up a bunch more use-cases. Basically, a collection could say: I am going to give you an index, but all I am going to guarantee about it is that it has properties X,Y, & Z (e.g. it is Strideable). Then I could pass it back to a function with the guarantee that it is the same type (even though I don't know type that was).

struct MyType {
    typealias PartId = some CustomStringConvertable

    func part(under point: CGPoint) -> PartId
    func selectPart(_ id:PartId)
}

Doesn't need to be in this version, but would be nice to know if that would eventually be possible. I can imagine that this might put strain on the type checker though if we don't have a way to give it a hint about what that type should be. Maybe you have to define the actual type as part of the typealias, but all that is exposed outside of the typealias is the opaque type...

(Michel Fortin) #32

Regarding composability, I suggested earlier that we need a way to name the opaque type to fix this. Apparently it "would be easy to add". Beside solving the comparability problem, I believe it would also be a good teaching tool.

It'd still be a nice gesture to see this acknowledged in future directions. It would indicate the author of the proposal understands there is a potential issue there and that it can be solved, even if only in a hypothetical future. It was a concern for more than one people in the previous review thread after all, so I too would have expected to see a mention of it.

I also note the "UI for generics" document is silent on this topic. I find it's a bit like looking very far ahead while missing the immediate issue right under our nose.

That said, adding a way to express the type name is something that can be fixed later. If it takes some pain to discover we need a way to name the type, then it's unfortunate but so be it.