# Multiple protocol conformances in extension macro

**URL:** <https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046>\
**Category:** Using Swift\
**Tags:** macros, attached-macros\
**Created:** [December 18, 2023, 4:36pm UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046 "2023-12-18T16:36:37Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Alan-Zip](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alan-zip/32/33381_2.png) [@Alan-Zip](https://forums.swift.org/u/Alan-Zip)\
**Post date:** [December 18, 2023, 4:36pm UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/1 "2023-12-18T16:36:37Z")

</div>

I'm trying to implement an extension macro that is capable of declaring conformances to two different protocols. [SE-0402](https://github.com/apple/swift-evolution/blob/main/proposals/0402-extension-macros.md) states:

- [The] protocols are specified in the `conformances:` list of the `@attached(conformances:)`

But I couldn't figure out how to do this for more than one protocol.

In code:

```swift
protocol A { }
protocol B { }

@attached(extension, conformances: A) // How do I add B as well?
public macro MyMacro() = #externalMacro(...)

```

I've tried `[A, B]`, `(A, B)`, `A, B`, and even `typealias C = A & B`, but of course none worked. Help!

---

<div class="post-metadata">

**Author:** ![rhx](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/rhx/32/14647_2.png) [@rhx](https://forums.swift.org/u/rhx)\
**Post date:** [December 18, 2023, 7:12pm UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/2 "2023-12-18T19:12:58Z")

</div>

You could do this through a protocol `C` that conforms to `A` and `B`:

```Swift
protocol C: A, B {}

@attached(extension, conformances: C)
public macro MyMacro() = #externalMacro(...)

```

---

<div class="post-metadata">

**Author:** ![Pippin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/pippin/32/24826_2.png) [@Pippin](https://forums.swift.org/u/Pippin)\
**Post date:** [December 18, 2023, 9:52pm UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/3 "2023-12-18T21:52:24Z")

</div>

You just add B like you did on your third attempt: `conformances: A, B`

Here's an example with Equatable and Hashable (which is a redundant conformance but not the point):

```swift
@attached(extension, conformances: Equatable, Hashable)
public macro equatable() = #externalMacro(...)

public struct EquatableMacro: ExtensionMacro {
    public static func expansion(...) throws -> [ExtensionDeclSyntax] {
        return [try ExtensionDeclSyntax("extension \(type.trimmed): Equatable, Hashable {}")]
    }
}

// usage

@equatable
struct MyStruct { }

// expands

extension MyStruct: Equatable, Hashable {}

```

---

<div class="post-metadata">

**Author:** ![Alan-Zip](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alan-zip/32/33381_2.png) [@Alan-Zip](https://forums.swift.org/u/Alan-Zip)\
**Post date:** [December 19, 2023, 6:35am UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/4 "2023-12-19T06:35:17Z")

</div>

> [@Pippin](#):
>
> You just add B like you did on your third attempt: `conformances: A, B`

Thank you @Pippin! That works indeed.

It seems my problem is caused by something else. In my project, protocol `B` inherits from protocol `A`:

```swift
public protocol A { }
public protocol B : A { }

```

And my experiments shows:

1. I can do this:

```swift
/// adds `extension MyStruct: B { }`
@attached(extension, conformances: B)
public macro MacroB() = #externalMacro(..., type: "Conform_B")

```

1. a. But I can't do this, where Xcode would tell me "Type 'MyStruct' does not conform to protocol 'A'":

```swift
/// adds `extension MyStruct: B { }`
@attached(extension, conformances: A, B)
public macro MacroB() = #externalMacro(..., type: "Conform_B")

```

1. b. (I can still do this though):

```swift
/// adds `extension MyStruct: A { }`
@attached(extension, conformances: A, B)
public macro MacroA() = #externalMacro(..., type: "Conform_A")

```

1. To keep `conformances: A, B`, I have to use this:

```swift
/// adds `extension MyStruct: A, B { }`
@attached(extension, conformances: A, B)
public macro MacroAB() = #externalMacro(..., type: "Conform_A_B")

```

Is this behavior documented/mentioned somewhere?

---

<div class="post-metadata">

**Author:** ![Alan-Zip](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alan-zip/32/33381_2.png) [@Alan-Zip](https://forums.swift.org/u/Alan-Zip)\
**Post date:** [December 19, 2023, 6:39am UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/5 "2023-12-19T06:39:57Z")

</div>

Thank you for the reply! Unfortunately I don't always want to conform to both the protocols, so I couldn't use this method.

---

<div class="post-metadata">

**Author:** ![Pippin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/pippin/32/24826_2.png) [@Pippin](https://forums.swift.org/u/Pippin)\
**Post date:** [December 19, 2023, 7:09am UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/6 "2023-12-19T07:09:16Z")

</div>

> [@Alan-Zip](#):
>
> In my project, protocol `B` inherits from protocol `A`:

Maybe I actually did use a relevant example. Since B inherits A, you only need to add that it conforms to B. For example, I could have removed the `Equatable` conformance and just used `Hashable`, which inherits from `Equatable`.

> [@Alan-Zip](#):
>
> a. But I can't do this, where Xcode would tell me "Type 'MyStruct' does not conform to protocol 'A'":

Then `MyStruct` isn't properly conforming to A, which it got from conforming to B. Are you sure the names are added correctly to the macro interface? I'm frankly unsure that about options 2 and 3, they seem to me like caching issues from the previous attempts. At this point, I don't know if this is a macro issue.

* * *

The following works, ~~but note that the protocol requirements for variables must not have a setter because variables are declared in an extension. I haven't read the threads that went over the evolution of these specific macros, but that seems like something that should be looked at (somehow allowing conformances for protocols with stored properties).~~

```swift
public protocol A {
    var foo: Int { get }
}
public protocol B: A { }

@attached(extension, conformances: B, names: named(foo))
public macro Conforming() = ...

public struct ConformingMacro: ExtensionMacro {
    public static func expansion(...) throws -> [ExtensionDeclSyntax] {
        // provide the requirements for A
        return [try ExtensionDeclSyntax("extension \(type.trimmed): B { var foo: Int { 420 } }")]
    }
}

// usage

@Conforming
struct MyStruct { }

// expands

extension MyStruct: B {
    var foo: Int {
        420
    }
}

```

Edit: Actually you can get away with a `get/set` for a protocol requirement with the good ol' private variable for the storage, been a while. While this may not have been your intention, just something for me to work on while making a presentation on macros.

> **Example P2**
>
> ```swift
> public protocol A {
> var foo: Int { get set }
> }
> public protocol B: A { }
> 
> @attached(extension, conformances: B, names: named(foo))
> @attached(member, names: named(_foo))
> public macro equatable() = ...
> 
> public struct EquatableMacro: ExtensionMacro, MemberMacro {
>     
> public static func expansion(...) throws -> [DeclSyntax] {
> return [DeclSyntax("private var _foo: Int = 420")]
> }
>     
> public static func expansion(...) throws -> [ExtensionDeclSyntax] {
> return [try ExtensionDeclSyntax("extension \(type.trimmed): B { var foo: Int { get { _foo } set { _foo = newValue } } }")]
> }
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![Alan-Zip](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alan-zip/32/33381_2.png) [@Alan-Zip](https://forums.swift.org/u/Alan-Zip)\
**Post date:** [December 19, 2023, 8:36am UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/7 "2023-12-19T08:36:15Z")

</div>

> [@Pippin](#):
>
> Maybe I actually did use a relevant example.

Haha indeed, I realized that right after I posted my reply.

But unfortunately, I don't always want to conform to protocol `B`. The macro decides whether to conform to `B` or just `A` according to the declaration it's added to. Therefore, I still need the `conformances: A, B`.

So, going back to my last post,

> [@Pippin](#):
>
> Then `MyStruct` isn't properly conforming to A, ...

I tested the code using a fresh macro template, and `A` and `B` are actual protocol as declared in the project, so they have no requirement at all. I also tested your code (P2), and indeed it works. But it breaks as soon as I change

```swift
@attached(extension, conformances: B, names: named(foo))

```

to

```swift
@attached(extension, conformances: A, B, names: named(foo))

```

Could you please test this in you environment and see if it behaves the same way?

---

<div class="post-metadata">

**Author:** ![Pippin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/pippin/32/24826_2.png) [@Pippin](https://forums.swift.org/u/Pippin)\
**Post date:** [December 19, 2023, 4:22pm UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/8 "2023-12-19T16:22:55Z")

</div>

> [@Alan-Zip](#):
>
> But it breaks as soon as I change

That actually is interesting. It does break when I add A, however that's only when I expand to B in the macro. When expanding to `extension Bar: A, B`, it works.

I am unsure if this is a bug or intended behavior. All `named()` declarations don't need to be in the expansion (I don't think it's checked) but to me it seems safer that the protocol conformances as declared must be in the expansion. I didn't read any language in the evolutions that said that this was required or missed it. However I am not that knowledgeable of macro implementation to know that much.

So at least right now, I don't think the macro system can do what you want. Personally, I would just have two macros that have separate A and B conformances which are used together.

---

<div class="post-metadata">

**Author:** ![Alan-Zip](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alan-zip/32/33381_2.png) [@Alan-Zip](https://forums.swift.org/u/Alan-Zip)\
**Post date:** [December 19, 2023, 4:51pm UTC](https://forums.swift.org/t/multiple-protocol-conformances-in-extension-macro/69046/9 "2023-12-19T16:51:27Z")

</div>

Thanks for checking! That's exactly the same behavior I'm observing.

For the time being, I just make the macro add `extension MyStruct: A, B { }` every time I need something to conform to `B`. Having two separate macros would in fact be a more reasonable choice, but I'm sticking with a single macro for now in order to introduce as few names as possible from my package.

I believe this could be a bug, since it's okay to have a macro that expands to `extension MyStruct: A { }`, or even an empty `ExtensionDeclSyntax` list, when the interface is `@attached(extension, conformances: A, B)`. Also the error is not properly reported, it's either "Type 'MyStruct' does not conform to protocol 'A", which is a false claim, or in many cases, just a non-zero return value.

I'll post a new topic later if I still think it's a bug after some more tests. Thank you again @Pippin for your help!
