# Infer associated type on protocol conformance

**URL:** <https://forums.swift.org/t/infer-associated-type-on-protocol-conformance/61166>\
**Category:** Using Swift\
**Tags:** typealias, associatedtype, protocol\
**Created:** [November 1, 2022, 5:55pm UTC](https://forums.swift.org/t/infer-associated-type-on-protocol-conformance/61166 "2022-11-01T17:55:30Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![mattcox](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattcox/32/10946_2.png) [@mattcox](https://forums.swift.org/u/mattcox)\
**Post date:** [November 1, 2022, 5:55pm UTC](https://forums.swift.org/t/infer-associated-type-on-protocol-conformance/61166/1 "2022-11-01T17:55:30Z")

</div>

I'm attempting to generalise `UIViewRepresentable` and `NSViewRepresentable` in my codebase into a single protocol called `ViewRepresentable`.

The idea being that a struct can conform to `ViewRepresentable`, and implicitly conform to `UIViewRepresentable` on iOS, and `NSViewRepresentable` on macOS. Although this sounds specific to SwiftUI, it is in fact a general problem.

My approach is like so:

```swift
#if os(iOS) || os(watchOS) || os(tvOS)
import UIKit

public protocol ViewRepresentable: UIViewRepresentable {
	associatedtype ViewType
	
	@MainActor
	func makeView(context: Context) -> ViewType
	
	@MainActor
	func updateView(_ view: ViewType, context: Context)
}

extension ViewRepresentable {
	@MainActor
	public func makeUIView(context: Context) -> UIViewType {
		makeView(context: context)
	}
	
	@MainActor
	public func updateUIView(_ uiView: UIViewType, context: Context) {
		updateView(uiView, context: context)
	}
}
#elseif os(macOS)
import AppKit

public protocol ViewRepresentable: NSViewRepresentable {
	associatedtype ViewType
	typealias NSViewType = ViewType
	
	@MainActor
	func makeView(context: Context) -> ViewType
	
	@MainActor
	func updateView(_ view: ViewType, context: Context)
}

extension ViewRepresentable {
	@MainActor
	public func makeNSView(context: Context) -> NSViewType {
		makeView(context: context)
	}
	
	@MainActor
	public func updateNSView(_ nsView: NSViewType, context: Context) {
		updateView(nsView, context: context)
	}
}
#endif

```

I want the struct that conforms to `ViewRepresentable` to not have to care if they are conforming to `UIViewRepresentable` or `NSViewRepresentable`, so they shouldn't have to specify the typealias for `NSViewType` or `UIViewType`, instead I want these to be inferred from them simply specifying the value of the `ViewType` typealias.

For example:

```swift
public struct SignInWithApple: ViewRepresentable {
	public typealias ViewType = ASAuthorizationAppleIDButton

	public func makeView(context: Context) -> ASAuthorizationAppleIDButton {
		ASAuthorizationAppleIDButton()
	}
	
	public func updateView(_ view: ASAuthorizationAppleIDButton, context: Context) {
		// . . .
	}
}

```

At the moment, this example above fails to compile, because either `NSViewType` or `UIViewType` has not been specified by the struct `SignInWithApple`.

My initial approach was to specify the typealias on the protocol or the extension, so something like this (I've removed the code that hasn't changed):

```swift
public protocol ViewRepresentable: UIViewRepresentable {
	typealias UIViewType = ViewType

	/// . . . etc
}

public protocol ViewRepresentable: NSViewRepresentable {
	typealias NSViewType = ViewType

	/// . . . etc
}

```

This gets things compiling, and solves my problem, but I get warnings:

`Typealias overriding associated type 'NSViewType' from protocol 'NSViewRepresentable' is better expressed as same-type constraint on the protocol`

`Typealias overriding associated type 'UIViewType' from protocol 'UIViewRepresentable' is better expressed as same-type constraint on the protocol`

I used the fix it, and it made sense:

```swift
public protocol ViewRepresentable: UIViewRepresentable where UIViewType == ViewType {
	/// . . . etc
}

public protocol ViewRepresentable: NSViewRepresentable where NSViewType == ViewType {
	/// . . . etc
}

```

The warning goes away, but the build fails because it expects the `SignInWithApple` doesn't conform to `ViewRepresentable`, because it doesn't specify the typealias `NSViewType` or `UIViewType`.

What am I doing wrong here? I can get it to build, with warnings, but the fix it for the warning introduces build errors. Is there a warning free fix I'm missing?

---

<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:** [November 1, 2022, 6:11pm UTC](https://forums.swift.org/t/infer-associated-type-on-protocol-conformance/61166/2 "2022-11-01T18:11:27Z")

</div>

Let me restate what I understand to be your question in a simplified way. Given:

```swift
protocol P { associatedtype A }
protocol Q: P where B == A { associatedtype B }

```

You are surprised that defining the following doesn't compile:

```swift
struct S: Q { typealias B = Int }
// Error: type 'S' does not conform to protocol 'Q'
// Error: type 'S' does not conform to protocol 'P'

```

...and nor (for that matter) does this:

```swift
struct S: Q { typealias A = Int }
// Error: type 'S' does not conform to protocol 'Q'

```

You'd like a way for a user to write a struct such as `S` that conforms to `P` via a more refined protocol such as `Q` without having to define the associated type `P.A`; rather, you'd like to allow `P.A` to be inferred from the associated type `Q.B`.

To do this, you can simply _restate_ the associate type requirement `A` in your more refined protocol `Q` _as an associated type with a default_ rather than a type alias:

```swift
protocol Q: P {
  associatedtype B
  associatedtype A = B
}
struct S: Q { typealias B = Int } // This compiles.

```

Note that this means something a bit different from what you're attempting to express with a `typealias` inside the protocol definition: in my version, the end user can actively choose to make the associated types `B` and `A` alias different concrete types, as the equivalence is just a default.

However, based on what you've described, I don't see anything that makes that unworkable, and in fact it may be an advantage (if, for example, they want an `NS...` type to be the associated type on macOS and a `UI...` type to be the associated type on other platforms).

---

<div class="post-metadata">

**Author:** ![mattcox](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattcox/32/10946_2.png) [@mattcox](https://forums.swift.org/u/mattcox)\
**Post date:** [November 1, 2022, 6:16pm UTC](https://forums.swift.org/t/infer-associated-type-on-protocol-conformance/61166/3 "2022-11-01T18:16:14Z")

</div>

Oh that makes much more sense. I was attempting to specify the type of A as a typelias, but specifying associated type makes sense.

Thanks.

---

<div class="post-metadata">

**Author:** ![mattcox](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattcox/32/10946_2.png) [@mattcox](https://forums.swift.org/u/mattcox)\
**Post date:** [November 1, 2022, 6:18pm UTC](https://forums.swift.org/t/infer-associated-type-on-protocol-conformance/61166/4 "2022-11-01T18:18:35Z")

</div>

So the final code becomes:

```swift
#if os(iOS) || os(watchOS) || os(tvOS)
import UIKit

public protocol ViewRepresentable: UIViewRepresentable where UIViewType == ViewType {
	associatedtype ViewType
	associatedtype UIViewType = ViewType
	
	@MainActor
	func makeView(context: Context) -> ViewType
	
	@MainActor
	func updateView(_ view: ViewType, context: Context)
}

extension ViewRepresentable {
	@MainActor
	public func makeUIView(context: Context) -> UIViewType {
		makeView(context: context)
	}
	
	@MainActor
	public func updateUIView(_ uiView: UIViewType, context: Context) {
		updateView(uiView, context: context)
	}
}
#elseif os(macOS)
import AppKit

public protocol ViewRepresentable: NSViewRepresentable where NSViewType == ViewType {
	associatedtype ViewType
	associatedtype NSViewType = ViewType
	
	@MainActor
	func makeView(context: Context) -> ViewType
	
	@MainActor
	func updateView(_ view: ViewType, context: Context)
}

extension ViewRepresentable {

	@MainActor
	public func makeNSView(context: Context) -> NSViewType {
		makeView(context: context)
	}
	
	@MainActor
	public func updateNSView(_ nsView: NSViewType, context: Context) {
		updateView(nsView, context: context)
	}
}
#endif

```

By including `where UIViewType == ViewType` and `where NSViewType == ViewType`, I can prevent the user from specifying a different value for `NSViewType`/`UIViewType` than `ViewType`.

Thanks again.
