# Protocol Witness Matching Roadmap

**URL:** <https://forums.swift.org/t/protocol-witness-matching-roadmap/60297>\
**Category:** Discussion\
**Tags:** protocol, roadmap, witness\
**Created:** [September 14, 2022, 9:00pm UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297 "2022-09-14T21:00:54Z")\
**Posts on this page:** 10\
**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:** [September 14, 2022, 9:00pm UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/1 "2022-09-14T21:00:55Z")

</div>

Hello Swift community,

Back in 2020, I started a thread [Protocol Witness Matching Mini-Manifesto](https://forums.swift.org/t/protocol-witness-matching-mini-manifesto/32752) to discuss the different kinds of witness matching ideas that the community has proposed, some design principles and which of those ideas we could potentially include in the language in the future.

It kicked off a really interesting (although limited) discussion, but it's been a long time since that thread was created, and I am really keen on getting the document into a state where it is comprehensive enough that it can be officially merged to the Swift repo.

So, I am looking for additional feedback and ideas from community members that we could incorporate into the roadmap - it could be new or existing ideas (for example: formalizing `@_implements`) for witness matching, feedback on the document structure or anything else that you think is useful.

Below is the current state of the roadmap, but I will be revising it based on the discussion here.

Thank you!

* * *

# Protocol Witness Matching Roadmap

Author: [Suyash Srijan](https://www.github.com/theblixguy)  
Last updated: April 24, 2020

### Jargon

Before we dive into the document, let's clarify some jargon:

- A _protocol requirement_ (or just _requirement_) is a declaration inside a protocol that all conforming types must satisfy.
- A _protocol witness_ (or just _witness_) is a value or a type that satisfies a protocol requirement.

For example:

```swift
protocol P {
  func foo() // This is a protocol requirement
}

struct S: P {
  func foo() { // This is a protocol witness
    ...
  }
}

```

## Introduction

In Swift (at the time of this writing), protocol witnesses have to pretty much match exactly with a protocol requirement. For example:

```swift
protocol P {
  func foo()
}

struct S: P {
  func foo() { ... }
}

```

```swift
protocol P {
  func getView() -> UIView
}

struct S: P {
  func getView() -> UIView { ... }
}

```

A few specific differences are allowed:

1. A non-throwing function can witness a throwing function requirement:

```swift
protocol P {
  func foo() throws
}

struct S: P {
  // Even though 'foo' here is not marked 'throws', it is
  // still able to satisfy the protocol requirement. The
  // caller has to handle the possibility that it might 
  // throw, but the witness is ofcourse free to throw or 
  // not to, depending on whether it makes sense in the
  // implementation.
  func foo() { ... }
}

```

1. A non-failable initializer can witness a failable initializer requirement:

```swift
protocol P {
  init?()
}

struct S: P {
  // Similarly, the initializer here is free to return
  // a newly created value or just return 'nil' instead.
  init() {}
}

```

1. A non-escaping closure can witness one that is marked `@escaping`:

```swift
protocol P {
  func foo(completion: @escaping() -> ()) 
}

struct S: P {
  // Similar to above, you can use a non-escaping closure here
  // if you want.
  func foo(completion: () -> ()) { ... }
}

```

1. A non-generic function requirement can be witnessed by a generic one:

```swift
struct Some {}

protocol P {
  func foo(arg: Some)
}

struct S: P {
  // This is okay, since 'foo' can accept any T, including 'Some'.
  // If T was constrained in a way that it couldn't accept 'Some',
  // then this (obviously) won't be a valid witness.
  func foo<T>(arg: T) {}
}

```

However, almost any other kind of mismatch is forbidden. For example:

```swift
protocol P {
  func getView() -> UIView
}

struct S: P {
  func getView() -> MyCustomUIViewSubclass { ... } // Not allowed
}

```

```swift
protocol P {
  init()
}

struct S: P {
  init(arg: Int = 0) { ... } // Not allowed
}

```

Many people have argued that the existing model is too restrictive and that more forms of mismatching should be allowed. It's also been suggested that the existing model feels inconsistent with other parts of the language; for example, the code example above where the witness's return type is a subclass of the requirement's return type is allowed with class method overrides. In order to figure out how respond to these statements, we first have to address a very basic question: what should the model be for how we expect witnesses to match with requirements?

This manifesto starts by listing some possible changes we could make that would allow more mismatches. It then sets out some design principles and describes some of the constraints on how the language can reasonably behave. Finally, it proposes a basic model for how witness matching should work in the language. The ultimate goal of this document is to provide a foundation for discussing witness matching in Swift and to spur a series of evolution proposals to bring the language into alignment with its proposed design.

## Likely

These are mismatches that aren't unreasonable to be allowed. Allowing this is mostly a matter of doing the implementation work and does not require any changes to the current syntax.

These forms of mismatching has also 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:

_Note: This has now been implemented in Swift 5.3. See [SE-0280](https://github.com/apple/swift-evolution/blob/master/proposals/0280-enum-cases-as-protocol-witnesses.md) for more details._

For example:

```swift
protocol P {
  static var foo: Self { get }
  static func bar(_ value: String) -> Self
}

enum E: P {
  case foo
  case bar(_ value: String)
}

let e: some E = E.foo

```

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

### Default arguments

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

```swift
protocol P {
  func bar(arg: Int)
}

struct S: P {
  func bar(arg: Int, anotherArg: Bool = true) { ... }
}

```

As a special case, we can also allow a function with all default arguments to witness a function requirement with no arguments:

```swift
protocol P {
  init()
}

struct S: P {
  init(arg1: Int = 0, arg2: Bool = false) { ... }
}

```

This seems reasonable, because the protocol really just requires the ability to call `init()` on the conforming type, which you can in this case since all arguments have default values.

Related bugs:

- None

### Subtyping

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

```swift
protocol P {
  func getView() -> UIView
}

struct S: P {
  func getView() -> MySubclassOfUIView { ... }
}

```

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 subtyping:

```swift
class A {
  func bar() -> Int? { ... }
}

class B: A {
  override func bar() -> Int { ... }
}

```

As we loosen the rules around subtyping and other kinds of matching, it is possible that associated type inference could degrade, so it is important to keep that in mind when working on this feature. 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 mismatches where either it's not clear whether it belongs to the language, whether it provides any concrete benefits, or it just complicates the existing design and/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 P {
  var bar: () -> Int
}

struct S: P {
  func bar() -> Int { ... }
}

```

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

```swift
protocol P {
  func bar() -> Int
}

struct S: P {
  var bar: () -> Int { ... }
}

```

### Syntactic matching

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

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

struct S: P {
  func bar(_ arg: Int) -> Bool { ... }
}

```

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

## Design Principles

The basic design principle is that matching shouldn't be entirely based on how the requirement is _written_ (or _spelled_), but rather it should be based on what the protocol requirement _semantically requires_. We probably do not want to take this principle to its extreme though and instead use it to provide a balance between language expressivity and complexity.

Here's a really simple example (which is allowed today):

```swift
protocol P {
  func foo(_ arg1: Int)
}

struct S: P {
  func foo(_ arg2: Int) { ... }
}

```

Here, the requirement is that a caller should be able to invoke a method `T.foo` (where `T` is a concrete type conforming to `P`) which takes a single argument of type `Int` which can be passed without the need to specify an argument name. One can argue that the parameter label should match too, however the name of that label is irrelevant because it does not change the semantics of the requirement, which is that "I should be able to call `foo` without an argument name".

However, this shouldn't be allowed (and isn't currently allowed):

```swift
protocol P {
  func foo(arg1: Int)
}

struct S: P {
  func foo(arg2: Int) { ... }
}

```

because the semantics of the function now have a fundamental difference i.e. you can no longer invoke `T.foo(arg1:)`. In this case, if we subsitute `T` with `S`, then `S.foo(arg1: 123)` is not a valid invocation.

Of course, we can allow people to work around it, by introducing a new language feature or re-using an existing one:

```swift
struct S: P {
  // Not currently allowed, but could be
  @_implements(P, foo(arg1:))
  func foo(arg2: Int) { ... }
}

```

However, that adds a lot of extra complexity for very little benefit; in fact, you now have to write _more_ code to work around it, whereas it's just simpler to rename the label.

Another example is a "subtype"-like semantic behavior:

```swift
protocol P {
  func foo() throws
}

struct S: P {
  func foo() { ... }
}

```

Even though `S.foo` is not marked `throws` (and `throws` is not really a type), a type `T -> U` can be thought of as a "subtype" of `T -> U throws`. Here, the requirement is that "I can call a function `foo` with no arguments and it _might_ throw". Now, whether `S.foo` throws or not depends on whether it makes sense to do so in the implementation. So, the semantics stay intact.

However, such "subtyping" should not be allowed in places where this is some sort of deeper guarantee. For example:

```swift
// Strawman annotation based on https://forums.swift.org/t/pitch-genericizing-over-annotations-like-throws
protocol P {
  func foo() alwaysthrows
}

struct S: P {
  func foo() throws { print("I didn't throw!") }
}

```

Here, `alwaysthrows` is a semantic guarantee; it says that the method will _always_ throw when it is called. However, `S.foo` may or may not throw. So, `T -> U throws` is not a "subtype" of `T -> U alwaysthrows`.

## A Basic Model

The basic model for witness matching would embrace the above design principles. Luckily, the current model already does that to some extent and by allowing the proposed changes we can align the model to be more in sync with what is reasonable to do.

In practice, this means:

- Exact matches are allowed
- Mismatches are allowed, as long as the semantic requirements are satisfied (for examples, a `throws` mismatch)
- Everything else is disallowed

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [September 14, 2022, 9:28pm UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/2 "2022-09-14T21:28:18Z")

</div>

> [@suyashsrijan](#):
>
> ### Properties with function type
> 
> We could allow a function to match a property protocol requirement with a function type. For example:
> 
> ```swift
> protocol P {
> var bar: () -> Int
> }
> 
> struct S: P {
> func bar() -> Int { ... }
> }
> 
> ```

I think this would be really cool if we could support it (well actually, the reverse case - witnessing a function requirement using a closure - is what I think would be useful).

It's a niche case, but... why not? If we're talking about members that are semantically equivalent (rather than syntactically identical), I think this would make sense.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [September 14, 2022, 9:51pm UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/3 "2022-09-14T21:51:18Z")

</div>

One thing I've been thinking about is that if we had a formalized version of `@_implements` then I think we could get most of the way towards the syntactic model for protocol witness matching without having a mess of complex _implicit_ witness matching rules.

The idea would be that annotating some declaration with `@implements(P, foo)` would synthesize the `P.foo` witness stub with a body that (syntactically) forwards to the annotated member. So rules like subtyping, closure/function equivalence, and maybe even things like dynamic member witnesses or default argument allowances. Concretely:

```swift
protocol P {
  func foo(x: Int) -> String?
}

struct S: P {
  @implements(P, foo)
  var bar: (Int) -> String
}

```

would implicitly synthesize something like:

```swift
func _S_P_foo(x: Int) -> String? {
  self.bar(x)
}

```

and all the expected conversions fall out naturally from existing language rules.

---

<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:** [September 14, 2022, 10:50pm UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/4 "2022-09-14T22:50:53Z")

</div>

> [@Jumhyn](#):
>
> One thing I've been thinking about is that if we had a formalized version of `@_implements` then I think we could get most of the way towards the syntactic model for protocol witness matching without having a mess of complex _implicit_ witness matching rules.

I think the full generality of `@_implements` would have to be strongly motivated on its own though.

I agree with the general problem statement that there already are witness matching rules, which as they exist currently are not fully rationalized and are limiting: some of the complexity actually lies in the fact that some intuitive rules surrounding mismatches are supported and others are not, and the distinction isn’t teachable.

I don’t think that merely allowing us to dispense with the (difficult) task of rationalizing these rules and filling in the missing bits is a good reason _per se_ to jump to `@_implements`. And for my part, even if `@_implements` were a formally specified feature, I wouldn’t consider it an answer to the question of why mismatches in `throws` are allowed for protocol witnesses but not mismatches in optionality, other than the case of failability for initializers.

Instead, I would agree with the premise of the roadmap that we do need to reckon with this directly, if we decide that this is an area worthy of tackling for the next language version.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [September 15, 2022, 12:17am UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/5 "2022-09-15T00:17:45Z")

</div>

> [@xwu](#):
>
> I don’t think that merely allowing us to dispense with the (difficult) task of rationalizing these rules and filling in the missing bits is a good reason _per se_ to jump to `@_implements`.

Definitely agree here—we still ought to consider what we want the overarching principle of witness matching to be and how to get there. But I also think that the potential of formalizing `@implements` gives good reason to err on the more restrictive rules when considering such a principle.

The _most_ restrictive version of such a principle is, of course, “exact signature matches only, everything else must use `@implements`,” and there’s a good amount of ground between that and the state of affairs today. IMO the process of rationalizing these rules reasonably results in us deciding to _remove_ bits where we may have gone too far with implicit matching rather than just “filling in.” This would come with the usual concerns about source compatibility and what we’re willing to break, but there too `@implements` would give a clear migration path.

Anyway, I’m not opposed to a hypothetical more-inclusive rule that ties all our implicit witness matching allowances together nicely. But I’m also very interested in ways that we can ergonomically minimize our implicit matching surface by making it very easy to _explicitly_ invoke witness matching (with the end goal still being explainability).

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [September 15, 2022, 12:48am UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/6 "2022-09-15T00:48:33Z")

</div>

> [@Jumhyn](#):
>
> But I also think that the potential of formalizing `@implements` gives good reason to err on the more restrictive rules when considering such a principle.  
> [...]  
> This would come with the usual concerns about source compatibility and what we’re willing to break, but there too `@implements` would give a clear migration path.

Not just that; the stricter these rules are, the more difficult it becomes to evolve protocols in a source-compatible way.

For example, I [mentioned](https://forums.swift.org/t/pre-pitch-explicit-protocol-fulfilment-with-the-conformance-keyword/60246/21) in a recent thread that I wanted a function returning a concrete type to be able to witness a requirement returning an existential. The idea was to write something like this:

```swift
protocol MyProto {
  #if swift(>=5.7)
    func doSomething() -> any Collection<UInt8>
  #else
    func doSomething() -> AnyCollection<UInt8>
  #endif
}

```

I've benchmarked algorithms using language-integrated existentials as being up to 80x faster than the same algorithm using the stdlib's versions, so I would really like to use them, but I still want this API to be available _in some form_ to people building with older compilers.

The idea is that those pre-5.7 users could write conformances like this:

```swift
struct MyStruct: MyProto {
  func doSomething() -> AnyCollection<UInt8> { ... }
}

```

And that when they eventually upgrade to 5.7, it would still match as a witness to the same requirement. Yes, the result would be an stdlib "existential" wrapped in a language existential, which is suboptimal for performance, but it would at least be a source-compatible change.

Since witness matching is too strict to allow for this kind of evolution, I'm having to limit this entire API to Swift 5.7+ with no compatibility fallback. It's the only part of the library that is limited in this way.

So yeah - while I understand the desire to make everything very strict, it can be impractical. We should be mindful of the benefits of being more relaxed, as long as everything still obeys some kind of comprehensible principles.

---

<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:** [September 15, 2022, 11:47am UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/7 "2022-09-15T11:47:05Z")

</div>

> [@suyashsrijan](#):
>
> ### Properties with function type
> 
> We could allow a function to match a property protocol requirement with a function type. For example:
> 
> ```swift
> protocol P {
> var bar: () -> Int
> }
> 
> struct S: P {
> func bar() -> Int { ... }
> }
> 
> ```
> 
> or vice versa - letting a function requirement be witnessed by a property with function type:
> 
> ```swift
> protocol P {
> func bar() -> Int
> }
> 
> struct S: P {
> var bar: () -> Int { ... }
> }
> 
> ```

I also second that this should be possible, especially after we finally resurrect and actually get '[compound names](https://forums.swift.org/t/compound-variable-names/37963)' in Swift.

---

<div class="post-metadata">

**Author:** ![Paul\_Cantrell](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/paul_cantrell/32/16764_2.png) [@Paul\_Cantrell](https://forums.swift.org/u/Paul_Cantrell)\
**Post date:** [September 18, 2022, 3:45pm UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/8 "2022-09-18T15:45:23Z")

</div>

Many ideas worthy of consideration here.

There are of course always hidden type-soundness pitfalls in ventures like this. I wonder: has anybody out there ever modeled Swift’s type system, or even just Swift’s protocol conformance rules, in Alloy or TLA+ or some such? That would be a wonderful way to test out the soundness of these proposals. Well beyond my expertise, I’m afraid…but I’ll bet somebody out there with the right skills could give us some surprising insights.

---

<div class="post-metadata">

**Author:** ![pierremb](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/pierremb/32/2020_2.png) [@pierremb](https://forums.swift.org/u/pierremb)\
**Post date:** [September 24, 2022, 5:57pm UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/9 "2022-09-24T17:57:58Z")

</div>

Very interesting initiative.

I feel the _likely_ part mostly comes down to covariance between the witness and the requirement (not sure in which direction).

> [@suyashsrijan](#):
>
> However, such "subtyping" should not be allowed in places where this is some sort of deeper guarantee. For example:
> 
> ```swift
> // Strawman annotation based on https://forums.swift.org/t/pitch-genericizing-over-annotations-like-throws
> protocol P {
> func foo() alwaysthrows
> }
> 
> struct S: P {
> func foo() throws { print("I didn't throw!") }
> }
> 
> ```
> 
> Here, `alwaysthrows` is a semantic guarantee; it says that the method will _always_ throw when it is called. However, `S.foo` may or may not throw. So, `T -> U throws` is not a "subtype" of `T -> U alwaysthrows`.

Wouldn’t `alwaysthrows` be expressible today as ˋthrows -\> Never`? In which case, the covariance rule would tell us the witness would need to be the same or just `-\> Never`.

---

<div class="post-metadata">

**Author:** ![cryo](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cryo/32/13218_2.png) [@cryo](https://forums.swift.org/u/cryo)\
**Post date:** [January 10, 2023, 1:44pm UTC](https://forums.swift.org/t/protocol-witness-matching-roadmap/60297/10 "2023-01-10T13:44:16Z")

</div>

> [@suyashsrijan](#):
>
> We can allow protocol witnesses to be covariant

I guess you mean: we can allow them to be covariant in their return types, and possibly contravariant in their argument types, right? That’s how subtyping seems to work.
