SE-0244: Opaque Result Types

Of the future directions described there, I can only see one that opaque typealiases address (aside from opaque typealiases themselves):

  • Opaque typealiases would be of limited use for describing opaque types in structural position; once you have more than one, you may want to impose constraints between them.
  • Opaque typealiases would have the exact same naming problem for describing where clause constraints, since with either opaque result types or with opaque typealiases, you need some way to describe the free type variables within the exposed interface of the opaque type. Using the typealias name itself would be as limiting as using a placeholder like _ for the return type case, since it only scales to a single free variable.
  • Opaque typealiases do indeed offer an obvious solution for conditional conformances, for which extension notation would be the obvious choice.
  • Opaque typealiases are completely independent of "opaque argument types". There is perhaps an alternative factoring of these features, where we have opaque typealiases, and then the "some" sugar is introduced uniformly for arguments (to introduce anonymous generic arguments) and returns (to introduce an anonymous opaque return typealias).

Those examples are trying to illustrate the use of method, though, not the feature itself. Opaque type aliases benefit the implementation of method() itself, where type inference doesn't help you like it can in the callers to method. I don't think that's a fair summary of the examples, though, since particularly in the introduction we provide some other examples of the kinds of library design this enables. The GameObject example is intended to be an example of where user code would use this feature heavily to interface with a generic library; it isn't intended to be just a niche library feature (and that's definitely not how the analogous feature has ended up in Rust, as I noted before).

I can understand your (and @Paul_Cantrell's) uncertainty about anonymous types, given that they're extremely ugly and problematic in C++ and other substitution-based languages. I think this feature as is has a few important benefits over anonymous types in those other languages. For a C++ lambda, all you really have to describe it is its source location, and because of the nature of C++'s type system, there's not really much you can do to abstract information about the type; as other templates get instantiated on the lambda, all you can do in C++ is snowball the type information into an avalanche of multi-page error messages when things go bad. On the other hand, the feature we're proposing is all about abstraction; it creates a separate entity the type system can reason about, and that entity is strongly tied to its source declaration, making it possible to refer to as "the return type of f" (and hey, in the fullness of time, we could maybe even allow type(of: f) to itself be used as a type). The opaque type hides the underlying implementation type, preventing the type avalanching problem C++ has, and is itself well-typed by its constraints, making it clear what its intended capabilities are.