# Protocol Witness Matching Mini-Manifesto

**URL:** <https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752>\
**Category:** Discussion\
**Tags:** protocols\
**Created:** [January 18, 2020, 7:22pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752 "2020-01-18T19:22:05Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [January 18, 2020, 7:22pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/1 "2020-01-18T19:22:05Z")

</div>

Hello Swift community,

I have been working on a "mini-manifesto" whose aim is to set out basic design principles around protocol witness matching and get some agreement from the Swift community on it. One of the reasons why is because I am currently [pitching](https://forums.swift.org/t/pitch-enum-cases-as-protocol-witnesses/32753) a new form of witness matching and while we've had some discussion on this forum on different kinds of matching (like subtyping, etc), it would be great to have a small document which people can refer to during discussions and use it to create new proposals to lift existing limitations.

This document is currently a draft so I would appreciate your thoughts and feedback on it. Thank you!

**Updated version here** : [[Docs] Add the Protocol Witness Matching mini-manifesto by theblixguy · Pull Request #29617 · swiftlang/swift · GitHub](https://github.com/apple/swift/pull/29617)

> * * *

# Protocol Witness Matching Manifesto (Draft)

Author: [Suyash Srijan](https://www.github.com/theblixguy)

(Note: This is a **work-in-progress** design document)

* * *

## Introduction

In Swift, protocol witnesses have to match exactly with a protocol requirement. For example:

```swift
protocol NetworkClient {
  func fetchRequest(request: URLRequest, numRetries: Int, completion: @escaping (Result<Data, Error>) -> Void)
}

class MyNetworkClient: NetworkClient {
  func fetchRequest(request: URLRequest, numRetries: Int, completion: @escaping (Result<Data, Error>) -> Void) { ... } // Okay
  func fetchRequest(request: URLRequest, numRetries: Int, completion: (Result<Data, Error>) -> Void) { ... } // Also okay
  func fetchRequest(request: URLRequest, numRetries, someArgument: Int = 0, completion: @escaping (Result<Data, Error>) -> Void) { ... } // Not a match
}

protocol ViewContainer {
  var base: UIView { get }
}

class MyViewContainer: ViewContainer {
  let base: UIView // Okay
  let base: MyCustomUIViewSubclass // Not a match
}

protocol FileDecoder {
  func decode() throws -> Data
  func encode(using encoder: FileEncoder)
}

class MyFileDecoder: FileDecoder {
  func decode() throws -> Data { ... } // Okay
  func decode() -> Data { ... } // Also okay
  
  func encode(using encoder: FileEncoder) { ... } // Okay
  func encode(using encoder: FileEncoder) throws { ... } // Not a match
}

```

with certain exceptions, such as:

1. A non-throwing function can witness a throwing function requirement.
2. A non-failable initializer can witness a failable initializer requirement.
3. A non-escaping closure can witness one that is marked `@escaping`.

Now, while some of the rules around matching a witness to a requirement are reasonable, others might argue that some of them are too restrictive (such as disallowing subtyping, which is already allowed in classes). This leads us to ask a very basic question - what kinds of differences are reasonable when matching a protocol witness to a protocol requirement?

This manifesto lists some possible changes we can make to the current model and set out some basic design principles. Some of these changes have been discussed many times in the past on the forums and while there is no guarantee that all of these changes will be implemented (either now or in the future), this document will serve as a starting point for discussions around witness matching (such as discussions around potential designs of how a certain feature mentioned here should work, whether its the right thing to do, etc) and something the community can use to create and publish evolution proposals.

## Likely

These are restrictions that are currently enforced by the compiler which are not unreasonable to be allowed and doing so is only a matter of doing the implementation work and does not require any changes to the current syntax.

These are also features that have been requested from time to time and can help improve the expressivity of the language, without fundamentally changing it.

### Desugaring

We can enable certain forms of "desugaring", such as allowing enum cases to satisfy static requirements:

For example:

```swift
protocol Number {
  static var zero: Self { get }
  static func one(times: Self) -> Self
}

enum MyNumber: Number {
  case zero
  indirect case one(times: Self)
}

let foo: some Number = MyNumber.one(times: .zero)

```

Enum cases already _behave_ like static properties/functions in the language, both syntactically and semantically, so it's reasonable to think of a case as "sugar" for it.

Related bugs:

- [[SR-3170] Enum cases should satisfy static var {get} protocol requirements · Issue #45758 · swiftlang/swift · GitHub](https://bugs.swift.org/browse/SR-3170)
- [[SR-9099] Enum case does not satisfy protocol static var · Issue #51596 · swiftlang/swift · GitHub](https://bugs.swift.org/browse/SR-9099)

### Default arguments

We can allow functions with default arguments to witness function requirements:

```swift
protocol NetworkClient {
  func fetch(request: URLRequest)
}

final class MyNetworkClient: NetworkClient {
  func fetch(request: URLRequest, retryCount: Int = 3) {
    ...
  }
}

```

Related bugs:

- None

### Subtyping

We can allow protocol witnesses to be covariant (i.e. have subtypes of the requirement):

```swift
protocol Scrollable {
  var base: UIView { get }
  func getView() -> UIView
}

final class MyScrollView: Scrollable {
  let base: MyCustomSubclassOfUIView
  
  func getView() -> AnotherSubclassOfUIView { 
    ...
  }
}

```

We already allow this in classes, so it probably makes sense for protocols witnesses to follow the same rules that exist for classes, for example, optional sub-typing:

```swift
class A {
  func getNumber() -> Int? { return 0 }
}

class B: A {
  override func getNumber() -> Int { return 0 }
}

```

As we loosen the rules around subtyping and other kinds of matching, it is possible that associated type inference could degrade and it is important to keep that in mind. There have been some ideas around how to improve it though, such as ones mentioned in [this](https://forums.swift.org/t/rfc-associated-type-inference/7168) post.

Related bugs:

- [[SR-522] Protocol funcs cannot have covariant returns · Issue #43139 · swiftlang/swift · GitHub](https://bugs.swift.org/browse/SR-522)
- [[SR-1950] Read-only protocol property requirements not satisfied by subtypes, when they should be · Issue #44559 · swiftlang/swift · GitHub](https://bugs.swift.org/browse/SR-1950)

Old PR with possible implementation: [https://github.com/apple/swift/pull/8718](https://github.com/apple/swift/pull/8718)

## Maybe/Unlikely

These are features where either it's not clear whether it belongs to the language or provides any concrete benefits, or it complicates the existing design or introduces other implementation/runtime complexity.

### Properties with function type

We could allow a function to match a property protocol requirement with a function type. For example:

```swift
protocol Fetchable {
  var fetch: () -> Data
}

struct MyFetchable: Fetchable {
  func fetch() -> Data { 
    ... 
  }
}

```

or vice versa - letting a function requirement be witnessed by a property with function type:

```swift
protocol Fetchable {
  func fetch() -> Data
}

struct MyFetchable: Fetchable {
  var fetch: () -> Data { 
    ... 
  }
}

```

### Syntactic matching

We could allow anything that meets the syntactic needs of the requirement to witness that requirement. For example:

```swift
protocol Mathable {
  static func isEven(_ instance: Self) -> (Int) -> Bool
}

struct Math: Mathable {
  func isEven(_ number: Int) -> Bool {
    ...
  }
}

```

We could go to the extreme and allow other kinds of matching, such as allowing `@dynamicMemberLookup` to satisfy arbitrary protocol requirements.

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [January 18, 2020, 8:37pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/2 "2020-01-18T20:37:57Z")

</div>

It seems to me that one opposite example is missing:

```swift
protocol Fetchable {
  func fetch() -> Data
  func fetch(foo: Foo) -> Data
}

strict S: Fetchable {
  var fetch: () -> Data { ... }

  // when compound names are supported
  var fetch(foo:): (Foo) -> Data { ... }

  // or with syntactic sugar
  var fetch: (foo: Foo) -> Data { ... }
}

```

> [@Extending declaration names for closures](https://forums.swift.org/t/extending-declaration-names-for-closures/10376):
>
> [SE-0111](https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md) was accepted with a small temporary regression of loosing parameter labels in closures. In an [extra commentary](https://lists.swift.org/pipermail/swift-evolution-announce/2016-July/000233.html) to this regression the core team pitched a solution that would be purely additive to the language without being a burden for the type system like pre SE-0111. The solution has to come in two steps: We have to extend the declaration names to allow labels in parentheses for variables, properties and parameters. (The following code snippet does not use , in between labels becau…

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [January 18, 2020, 8:54pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/3 "2020-01-18T20:54:11Z")

</div>

Also I‘d love to see a generalization over Optional being a super type.

This is related:

> [@How does this rule work in regard of ambiguity?](https://forums.swift.org/t/how-does-this-rule-work-in-regard-of-ambiguity/19448/2):
>
> ![](https://global.discourse-cdn.com/swift/original/2X/2/2f4a7adb764fc71054999c1674391ae9c6f9d52f.jpeg) DevAndArtist:
> 
> > - Would it make any sense to allow protocol requirement satisfaction with non-optional types, like with failable init's? (Probably with some implicit optional promotion.)
> 
> Yep, totally! Except for the part where this changes the behavior of existing code, so we'd have to be very careful about it. This is considered part of [[SR-522] Protocol funcs cannot have covariant returns ](https://bugs.swift.org/browse/SR-522).

---

<div class="post-metadata">

**Author:** ![beccadax](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/beccadax/32/34217_2.png) [@beccadax](https://forums.swift.org/u/beccadax)\
**Post date:** [January 18, 2020, 9:01pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/4 "2020-01-18T21:01:23Z")

</div>

> **Corrected mistake**
>
> > [@suyashsrijan](#):
> >
> > We can allow functions with default arguments to witness function  
> > requirements:
> > 
> > ```swift
> > protocol NetworkClient {
> > func fetch(request: URLRequest, retryCount: Int)
> > }
> > 
> > final class MyNetworkClient: NetworkClient {
> > func fetch(request: URLRequest, retryCount: Int = 3) {
> > ...
> > }
> > }
> > 
> > ```
> 
> Small correction: What you wrote is fine. What isn’t allowed is using a defaulted argument to match a requirement with no argument at all:
> 
> ```swift
> protocol NetworkClient {
> func fetch(request: URLRequest)
> }
> 
> final class MyNetworkClient: NetworkClient {
> func fetch(request: URLRequest, retryCount: Int = 3) {
> ...
> }
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [January 18, 2020, 9:07pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/5 "2020-01-18T21:07:42Z")

</div>

Oops, thank you for spotting my mistake. I'll fix it!

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [January 18, 2020, 9:12pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/6 "2020-01-18T21:12:47Z")

</div>

I think `Fetchable` example is also incorrect, because `MyFetchable` should be a conforming type, no?

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [January 18, 2020, 9:15pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/7 "2020-01-18T21:15:23Z")

</div>

Thank you, I have fixed it now!

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [January 19, 2020, 9:19am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/8 "2020-01-19T09:19:53Z")

</div>

This rule would likely be arbitrary subtyping, which includes optionals, like it is with class overrides.

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [January 20, 2020, 9:07am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/9 "2020-01-20T09:07:08Z")

</div>

Moving the discussion from the other thread into here:

> [@Enum cases as protocol witnesses](https://forums.swift.org/t/enum-cases-as-protocol-witnesses/32753/89):
>
> I think in that case we would have to change the outcome of SE-0155 which banned `case foo()` . There isn't a way to write a `case foo` with type `(T.Type) -> () -> T` today.

So either the default argument feature from above cannot be reduced to zero arguments or I still don‘t understand something here.

```swift
protocol P {
  static func foo() -> Self
}

struct S: P {
  static func foo(_ s: S = .init()) -> S { s } // #1 is this okay?
}

enum E: P {
  case foo(Void = ()) // if #1 is okay then this should be okay as well
}

```

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [January 20, 2020, 9:14am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/10 "2020-01-20T09:14:22Z")

</div>

Are you thinking of `case foo(Void = ())` to be the same as just a `case foo` (or do you want it to be the same)? Because they are not the same at the moment:

```swift
enum Foo: Equatable {
  case bar1(Void = ())
  case bar2

  // Probably not needed when tuples are equatable
  static func == (lhs: Self, rhs: Self) -> Bool {
	switch (lhs, rhs) {
	  case (.bar1, .bar1): return true
	  case (.bar2, .bar2): return true
	  default: return false
    }
  }
}

let b1 = Foo.bar1()
let b2 = Foo.bar2

b1 == .bar1 // error
b1 == .bar1() // okay
b2 == .bar2 // okay, as usual

```

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [January 20, 2020, 9:21am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/11 "2020-01-20T09:21:22Z")

</div>

Again, I‘m not talking about a payload less enum case at all. My thinking path is that `case foo(Int = 42)` would satisfy `static func foo() -> Self` if #1 in the above example would be valid.

Then you can do:

```swift
func test<T: P>(_: T.Type) -> T {
  T.foo()
}

let e = test(E.self)
// E is from an example upthread, it‘s payload has Void not Int, 
// but it does not matter, in can be anything
e == .foo() // assuming Void is Equatable

```

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [January 20, 2020, 9:28am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/12 "2020-01-20T09:28:16Z")

</div>

Okay, sorry I misunderstood what you were talking about. I think it might be okay for that to work (i.e. a function with _all_ default arguments can witness a function which takes no arguments).

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [January 20, 2020, 6:10pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/13 "2020-01-20T18:10:26Z")

</div>

> [@John\_McCall](#):
>
> This rule would likely be arbitrary subtyping, which includes optionals, like it is with class overrides.

@suyashsrijan I think this would be important to incorporate into the text of the mini-manifesto. There is also a prior PR, never merged and closed for inactivity, to make this work in the case of optionals, which would be good to link to for reference.

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [January 20, 2020, 6:16pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/14 "2020-01-20T18:16:53Z")

</div>

Ah yes, I remember that PR. I have updated the text now, thank you!

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [January 21, 2020, 11:34pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/15 "2020-01-21T23:34:28Z")

</div>

> [@suyashsrijan](#):
>
> ### Subtyping
> 
> We can allow protocol witnesses to be covariant (i.e. have subtypes of the requirement):

One thing to keep in mind: as the witness matching rules get more complex, it has a spillover effect on associated type inference rules becoming more complex and possibly less predictable.

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [January 21, 2020, 11:59pm UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/16 "2020-01-21T23:59:10Z")

</div>

> [@Slava\_Pestov](#):
>
> One thing to keep in mind: as the witness matching rules get more complex, it has a spillover effect on associated type inference rules becoming more complex and possibly less predictable.

Is that still true if we push through the changes to inference that @Douglas_Gregor pitched last year?

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [January 22, 2020, 2:16am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/17 "2020-01-22T02:16:56Z")

</div>

Are you referring to [this](https://forums.swift.org/t/infer-associated-types-as-generic-parameters-more-eagerly/30833)? I do remember associated type inference concerns being raised in the past whenever the topic of covariance has come up. I’m not familiar with the implementation so I’m not sure how exactly one would go about solving it (maybe Doug has some ideas?) but I’ll add Slava’s point as a note in the document so it can be referred to in the future.

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [January 22, 2020, 2:58am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/18 "2020-01-22T02:58:22Z")

</div>

> [@suyashsrijan](#):
>
> Are you referring to [this](https://forums.swift.org/t/infer-associated-types-as-generic-parameters-more-eagerly/30833)?

Nope, I was referring to this: [[RFC] Associated type inference](https://forums.swift.org/t/rfc-associated-type-inference/7168). Looks like it was actually a couple years ago now.

---

<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:** [January 22, 2020, 5:47am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/19 "2020-01-22T05:47:45Z")

</div>

> [@anandabits](#):
>
> Nope, I was referring to this: [[RFC] Associated type inference ](https://forums.swift.org/t/rfc-associated-type-inference/7168). Looks like it was actually a couple years ago now.

I still think we need to nail down associated type inference to make it more predictable and more efficiently implementable. Loosening the witness matching requirements might make the current system a little more complicated, and we should be mindful of that... but we shouldn't let it get in the way of improving on this area.

Doug

---

<div class="post-metadata">

**Author:** ![omochimetaru](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/omochimetaru/32/9598_2.png) [@omochimetaru](https://forums.swift.org/u/omochimetaru)\
**Post date:** [February 10, 2020, 4:27am UTC](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752/20 "2020-02-10T04:27:57Z")

</div>

I propose to write a pattern below in `Introduction` section.

```swift
protocol P1 {}

struct S1: P1 {}

protocol P2 {
    func foo(_ p1: S1)
}

struct S2: P2 {
    func foo<X: P1>(_ p1: X) {}
}

```

Generic function can conform to requirements.  
This technique is useful sometime.

[Next page](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752.md?page=2)
