# SE-0244: Opaque Result Types

**URL:** <https://forums.swift.org/t/se-0244-opaque-result-types/21252>\
**Category:** Proposal Reviews\
**Created:** [March 5, 2019, 9:40pm UTC](https://forums.swift.org/t/se-0244-opaque-result-types/21252 "2019-03-05T21:40:52Z")\
**Posts on this page:** 1\
**Showing post:** 148

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [March 18, 2019, 8:01am UTC](https://forums.swift.org/t/se-0244-opaque-result-types/21252/148 "2019-03-18T08:01:04Z")

</div>

> [@Joe\_Groff](#):
>
> - They lose one of the primary benefits of the Rust feature, which is the ability to directly describe a function's return interface without the indirection of another name. Furthermore, this feature is competing directly with existential types in that "hide the concrete return type" role; we know existentials are inadequate in that role for all the reasons the proposal outlines, but if it takes a second decl, a restatement of the concrete underlying type, and coming up with a new name to take advantage of opaque types, then existentials will still look syntactically attractive as an alternative.

I went fairly far down the path of designing opaque type aliases, and for me they fell into this mid-point between opaque result types as-proposed and a more powerful forwarding abstraction.

Opaque type aliases are too heavy for the first motivating example in the proposal:

```swift
opaque typealias CompactMapCollection<Elements, ElementOfResult>: Collection where .Element == ElementOfResult
  = LazyMapSequence<LazyFilterSequence<LazyMapSequence<Elements, ElementOfResult?>>, ElementOfResult>

extension LazyMapCollection {
  public func compactMap<ElementOfResult>(
    _ transform: @escaping (Elements.Element) -> ElementOfResult?
  ) -> CompactMapCollection<Elements, ElementOfResult> {
    return self.map(transform).filter { $0 != nil }.map { $0! }
  }
}

```

That opaque type alias `CompactMapCollection` is difficult to write in the first place. We gained no clarity by writing it out, and we really can't even come up with a name that's more meaningful than "the result of compactMap."

With opaque result types, this would be:

```swift
extension LazyMapCollection {
  public func compactMap<ElementOfResult>(
    _ transform: @escaping (Elements.Element) -> ElementOfResult?
  ) -> some Collection where .Element == ElementOfResult
    return self.map(transform).filter { $0 != nil }.map { $0! }
  }
}

```

The same information is there, but without the extra declaration or the ugly type that needs to be synchronized with the body of `compactMap`. Note that in both cases I'm assuming we have the `where` syntax to add additional constraints (on the `Element` of the hidden type)---you need that in both SE-0244 and the opaque typealias proposal, although it's not outlined or used in the latter. I feel like Greg Titus [made this argument well](https://forums.swift.org/t/opaque-result-types/15645/123) back in the pitch phase; it's part of what made me realize how much we were giving up in simplicity of use when the design started shifting toward opaque type aliases.

On the other hand, it would be nice if it were easy to have a named type that I can implement in terms of another type, but hide my implementation details. An opaque typealias would let me do that in one way, but it means that my named type can only be an alias for some other type---it _can't_ have it's own identity.

Back in the pitch for this proposal, the question "is an opaque type alias really `newtype`?" came up. [`newtype`](https://wiki.haskell.org/Newtype) is a Haskell construct that creates a new, unique type whose implementation is provided by another type. If you had such a thing in Swift, it would look a lot like opaque type aliases: you would define a new name, provide the (hidden) underlying type, and forward along some protocol conformances to state its initial capabilities. However, unlike with opaque type aliases, you could write an `extension` on the `newtype` that would only apply to the new type and not the underlying type, make it conform to protocols on its own, etc.

But once you look at `newtype`, you realize that it's not all that different from declaring a new `struct` with a single stored property (the underlying value) and then forwarding conformances along. @anandabits has a proposal draft for [protocol forwarding](https://forums.swift.org/t/proposal-draft-automatic-protocol-forwarding/817) that demonstrates this (it predates the switch to Discourse, so the formatting is a mess) that I find compelling. For example, it would help you implement a `Meters` type as a `struct` containing a `Double`, and then forward the `FloatingPoint` APIs so you get a unique type that let's you perform numeric computation with just a few lines of code.

For me, opaque type aliases fall into this uncanny middle ground between "lightweight way to hide a result type that's hard to write and reason about" and "useful feature for building new types." It solves neither problem well, but if it's there people will reach for it and not get what they want.

Doug

---

_[View the full topic](https://forums.swift.org/t/se-0244-opaque-result-types/21252)._
