# What are the rules on inheriting associated types from protocols?

**URL:** <https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757>\
**Category:** Using Swift\
**Created:** [July 7, 2022, 5:18pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757 "2022-07-07T17:18:50Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![anon9791410](https://avatars.discourse-cdn.com/v4/letter/a/9fc348/32.png) [@anon9791410](https://forums.swift.org/u/anon9791410)\
**Post date:** [July 7, 2022, 5:18pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/1 "2022-07-07T17:18:50Z")

</div>

I've never been too clear on how associated types and type aliases trickle down from parent protocols. Here's a simplified version of a real relevant `Collection`-y problem. Can this error…

`Reference to invalid associated type 'Index' of type 'S'`

…be resolved without having to manually use `Int` within `S` or one of its extensions, if the `subscript` does indeed need to be defined at the level of `S` and not higher up the chain?

```swift
public protocol P: RandomAccessCollection where Index == Int {}

extension P {
  public var startIndex: Index { 0 }
}

```

```swift
public struct S { }

extension S: P {
  public var endIndex: Index { 0 }
  public subscript(index: Index) -> Void { () }
}

```

---

<div class="post-metadata">

**Author:** ![Mordil](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mordil/32/5840_2.png) [@Mordil](https://forums.swift.org/u/Mordil)\
**Post date:** [July 7, 2022, 5:57pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/2 "2022-07-07T17:57:51Z")

</div>

If you declare it as `struct S: P` does the compiler error go away? Or if you try the latest 5.7 compiler, does that improve it?

---

<div class="post-metadata">

**Author:** ![anon9791410](https://avatars.discourse-cdn.com/v4/letter/a/9fc348/32.png) [@anon9791410](https://forums.swift.org/u/anon9791410)\
**Post date:** [July 11, 2022, 4:55pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/3 "2022-07-11T16:55:54Z")

</div>

> [@Mordil](#):
>
> If you declare it as `struct S: P` does the compiler error go away? Or if you try the latest 5.7 compiler, does that improve it?

1. No.

2. Different sort of no. I wouldn't try a thing with a lower version anymore.

---

<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:** [July 11, 2022, 5:17pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/4 "2022-07-11T17:17:45Z")

</div>

> [@anon9791410](#):
>
> `public protocol P: RandomAccessCollection where Index == Int {}`

Your code example works if I write:

```swift
public protocol P: RandomAccessCollection where Index == Int {
  associatedtype Index
}

```

"Re-stating" an associated type in this manner is a no-op -- the generics implementation doesn't consider it as a distinct entity from Index in the parent protocol, which is constrained to Int -- but it helps nudge associated type inference into figuring out what's going on.

This is a bug and we should fix it some day, but it's not quite as straightforward to fix I think. Associated type inference in general is kind of broken and needs a complete overhaul.

---

<div class="post-metadata">

**Author:** ![anon9791410](https://avatars.discourse-cdn.com/v4/letter/a/9fc348/32.png) [@anon9791410](https://forums.swift.org/u/anon9791410)\
**Post date:** [July 11, 2022, 6:09pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/5 "2022-07-11T18:09:00Z")

</div>

The use case I tried to simplify isn't solved by your suggestion. Is it currently solvable with another trick?

```swift
public protocol BackedByInteger
: ExpressibleByIntegerLiteral & Hashable & MutableCollection & RandomAccessCollection
where Index == Int {
  associatedtype Integer: FixedWidthInteger & _ExpressibleByBuiltinIntegerLiteral
  
  init(_: Integer)
}

// MARK: - ExpressibleByIntegerLiteral
extension BackedByInteger {
  public init(integerLiteral integer: Integer) {
    self.init(integer)
  }
}

// MARK: - MutableCollection, RandomAccessCollection
extension BackedByInteger {
  public var startIndex: Index { 0 }
}

```

```swift
/// The bits of an integer, from least significant to most.
public struct Bits<Integer: FixedWidthInteger & _ExpressibleByBuiltinIntegerLiteral> {
  public var integer: Integer
}

// MARK: - Collection
extension Bits: BackedByInteger {
  public var endIndex: Index { Integer.bitWidth }

  public subscript(index: Index) -> Integer {
    get { integer >> index & 1 }
    set {
      integer &= ~(1 << index)
      integer |= (newValue & 1) << index
    }
  }
}

// MARK: - BackedByInteger
extension Bits {
  public init(_ integer: Integer) {
    self.integer = integer
  }
}

```

```swift
/// The nybbles of an integer, from least significant to most.
public struct Nybbles<Integer: FixedWidthInteger & _ExpressibleByBuiltinIntegerLiteral> {
  public var integer: Integer
}

// MARK: - Collection
extension Nybbles {
  public var endIndex: Index { Integer.bitWidth / 4 }

  public subscript(index: Index) -> Integer {
    get { integer >> (index * 4) & 0xF }
    set {
      let index = index * 4
      integer &= ~(0xF << index)
      integer |= (newValue & 0xF) << index
    }
  }
}

// MARK: - BackedByInteger
extension Nybbles: BackedByInteger {
  public init(_ integer: Integer) {
    self.integer = integer
  }
}

```

---

<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:** [July 11, 2022, 6:57pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/6 "2022-07-11T18:57:08Z")

</div>

> [@anon9791410](#):
>
> The use case I tried to simplify isn't solved by your suggestion. Is it currently solvable with another trick?
> 
> ```swift
> 
> ```

Can you try adding a declaration `associatedtype Index` to protocol `BackedByInteger`?

---

<div class="post-metadata">

**Author:** ![anon9791410](https://avatars.discourse-cdn.com/v4/letter/a/9fc348/32.png) [@anon9791410](https://forums.swift.org/u/anon9791410)\
**Post date:** [July 11, 2022, 8:58pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/7 "2022-07-11T20:58:23Z")

</div>

That's what I'm saying—it works for the simplified example but not there.

I don't like having to make the arbitrary decision of the one place to put `Int` so I just restructured the whole concept 🫠:

> **SmallIntegerCollection**
>
> ```swift
> public extension BinaryInteger {
> /// The bits of an integer, from least significant to most.
> var bits: SmallIntegerCollection<Self> {
> get { .init(container: self, elementBitWidth: 1) }
> set { self = newValue.container }
> }
> 
> /// The nybbles of an integer, from least significant to most.
> var nybbles: SmallIntegerCollection<Self> {
> get { .init(container: self, elementBitWidth: 4) }
> set { self = newValue.container }
> }
> }
> 
> /// A collection of integers which "fit" into a larger integer type.
> ///
> /// `Container` is an integer that can contain `Container.bitWidth / elementBitWidth` elements.
> /// `SmallIntegerCollection` divides it evenly; indexing is performed from least significant divisions to most.
> public struct SmallIntegerCollection<Container: BinaryInteger> {
> public init(container: Container, elementBitWidth: Int) {
> self.container = container
> self.elementBitWidth = elementBitWidth
> }
> 
> /// The backing storage unit for this collection.
> public var container: Container
> 
> /// The number of bits needed for the underlying binary representation of each element of this collection.
> public var elementBitWidth: Int
> }
> 
> // MARK: - public
> public extension SmallIntegerCollection {
> /// An element with `1` for all bits.
> var mask: Container { ~(~0 << elementBitWidth) }
> }
> 
> // MARK: - MutableCollection & RandomAccessCollection
> extension SmallIntegerCollection: MutableCollection & RandomAccessCollection {
> public typealias Index = Int
> 
> public var startIndex: Index { 0 }
> public var endIndex: Index { Container().bitWidth / elementBitWidth }
> 
> public subscript(index: Index) -> Container {
> get { container >> (index * elementBitWidth) & mask }
> set {
> let index = index * elementBitWidth
> container &= ~(mask << index)
> container |= (newValue & mask) << index
> }
> }
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![anon9791410](https://avatars.discourse-cdn.com/v4/letter/a/9fc348/32.png) [@anon9791410](https://forums.swift.org/u/anon9791410)\
**Post date:** [August 11, 2022, 6:42am UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/8 "2022-08-11T06:42:09Z")

</div>

More sadness now that primary associated types are thrown into the mix:

> An associated type named 'Key' must be declared in the protocol 'ExpressibleByKeyValuePair' or a protocol it inherits

```swift
public protocol ExpressibleBy2Tuple {
  associatedtype Element0
  associatedtype Element1

  init(_: (Element0, Element1))
}

public protocol ExpressibleByKeyValuePair<Key, Value>: ExpressibleBy2Tuple {
  typealias Key = Element0
  typealias Value = Element1
}

```

---

<div class="post-metadata">

**Author:** ![wes1](https://avatars.discourse-cdn.com/v4/letter/w/848f3c/32.png) [@wes1](https://forums.swift.org/u/wes1)\
**Post date:** [August 11, 2022, 6:17pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/9 "2022-08-11T18:17:24Z")

</div>

> [@Slava\_Pestov](#):
>
> Associated type inference in general is kind of broken and needs a complete overhaul

fwiw, these are the problems leading me to turn away from Swift.

I regularly hit associated-type problems I cannot solve or even understand. I've been a staff engineer for multiple large teams and once worked on a programming language. Jessy is a long-time and deep contributor. We should be able to get these sorted without forum posts. Previously, I've held out hope that I'm simply misguided, and will eventually get the correct understanding.

Now the prospect that they're (design?) bugs too hard to fix has huge implications for the projects I'm planning. I'm deeply saddened, really, because I've grown to love Swift.

I'm very grateful for direct confession of flaws, because that helps with partial solutions -- avoidance or moving forward via workarounds. Any pointers to bugs or discussions characterizing the problem would be welcome. 🙏

---

<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:** [August 11, 2022, 6:20pm UTC](https://forums.swift.org/t/what-are-the-rules-on-inheriting-associated-types-from-protocols/58757/10 "2022-08-11T18:20:11Z")

</div>

> [@wes1](#):
>
> I regularly hit associated-type problems I cannot solve or even understand.

Are we talking about associated type inference or are you having trouble learning Swift generics and protocols with associated types in general?

> [@wes1](#):
>
> Now the prospect that they're (design?) bugs too hard to fix has huge implications for the projects I'm planning. I'm deeply saddened, really, because I've grown to love Swift.

"Associated type inference" is the specific feature that inserts implicit typealiases into types that implement protocols with associated types. Here is a simple case:

```swift
protocol P {
  associatedtype A
  func f() -> A
}

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

```

You can omit the `typealias A = Int` in `struct S` because it's inferred from `f()`.

You can usually just define the type aliases yourself instead, writing this also works fine:

```swift
struct S: P {
  typealias A = Int
  func f() -> Int {}
}

```

There are bugs with some more complex cases of the above but they are certainly not too hard to fix, it just needs some focused effort in this area.
