# Protocol metatype extensions (to better support SwiftUI)

**URL:** <https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469>\
**Category:** Pitches\
**Created:** [June 8, 2019, 9:00pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469 "2019-06-08T21:00:11Z")\
**Posts on this page:** 20\
**Page:** 1

<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:** [June 8, 2019, 9:00pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/1 "2019-06-08T21:00:11Z")

</div>

Swift's dot shorthand for static factories is wonderful! Unfortunately, it currently requires a concrete type context in order to work. A while ago I [pitched an idea](https://forums.swift.org/t/make-dot-shorthand-work-with-generics-and-existentials/19324) for lifting this limitation. It turned out that the original idea in that pitch isn't viable, but the thread did lead to some interesting discussion that pointed in a potentially more viable direction.

### SwiftUI

SwiftUI is using the workaround I described in the form of [`StaticMember`](https://developer.apple.com/documentation/swiftui/staticmember). Desipite having developed the workaround and used it in a few projects, it took some head scratching before I recognized the role `StaticMember` was playing in SwiftUI. Quoting the documentation:

> Use StaticMember to support implicit member expressions, sometimes referred to as leading dot syntax, where they would normally not be supported, like static properties representing concrete values provided to a protocol-constrained generic function. For example:

```swift
protocol ColorStyle {
    typealias Member = StaticMember<Self>
}

extension StaticMember where Base : ColorStyle {
    static var red: RedStyle.Member { return .init(.init()) }
    static var blue: BlueStyle.Member { return .init(.init()) }
}

extension View {
    func colorStyle<S : ColorStyle>(_ style: S.Member) -> some View {
        ...
    }
}

MyView().colorStyle(.red)
MyView().colorStyle(.blue)

```

As an Apple framework that will live a very long life, I don't think SwiftUI should be introducing a workaround like this. I think we should revisit this topic and introduce proper langauge support if at all possible. If one isn't possible we should consider moving `StaticMember` into the standard library as a standard workaround everyone in the community can become familiar with and share.

### Previous discussions and big picture

As I mentioned, the earlier thread on this topic pointed in some interesting directions and I continued to think about it. This thinking lead to [a broad sketch](https://forums.swift.org/t/improving-the-ui-of-generics/22814/74) for a direction in which we are able to extend metatypes and existentials in additiona to concrete types. Discussion of that sketch [led to a design](https://forums.swift.org/t/improving-the-ui-of-generics/22814/86) that uses the `meta` keyword for extending metatypes. (It also builds on the `any` and `some` keywords that are a part of [Improving the UI of generics](https://forums.swift.org/t/improving-the-ui-of-generics/22814))

At a high level, this design sketched at the above links enables the following forms of extensions (among others):

- `extension P` contionues to extend both conforming types _and_ the existential as it does today
- `extension any P` extends a protocol existential only (not conforming types or the metatype)
- `extension some P` extends conforming types onyl (not the existential or the metatype)
- `extension meta P` extends the protocol metatype only (not the existentia or conforming types)

### Proposed solution

I propose that we shoud introduce protocol metatype extensions and use those to drive dot shorthand in generic contexts. The above SwiftUI code would be streamlined as follows:

```swift
protocol ColorStyle {}

extension meta ColorStyle {
    static var red: RedStyle { return .init() }
    static var blue: BlueStyle { return .init() }
}

extension View {
    func colorStyle<S : ColorStyle>(_ style: S) -> some View {
        ...
    }
}

MyView().colorStyle(.red)
MyView().colorStyle(.blue)

// Static members of the protoco metatype may be accessed explicitly as well
let myStyle = ColorStyle.red

// Conforming values stored in variables are directly compatible with the generic API
// which is not the case with APIs based on a `StaticMember` wrapper type
MyView().colorStyle(myStyle)

```

In this design, dot shorthand will consider all static members of the protocol metatype which return a value of a conforming type. This removes the need for a wrapper type and streamlines the API of the library. It also improves support for passing variables of conforming types directly to an API.

Without direct language support for this shorthand a library author is left with two bad choices if it wishes to support both dot shorthand and direct values. One choice is to require users to wrap values of conforming types. The other is to provide two overloads, one taking a conforming value and the other using a wrapper to drive the use of dot shorthand. The first option forces additional syntax on users of the library. The latter introduces a lot of boilerplate into the library and creates potential for ambiguity. Both options may cause confusion for users of the library who may not understand the design.

In summary, let's bridge the gap between dot shorthand and generics so these language features are more directly compatibe with each other. (And let's do it before SwiftUI ships with a workaround)

---

<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:** [June 8, 2019, 9:10pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/2 "2019-06-08T21:10:47Z")

</div>

I'm all for brining `meta` into the language and cleaning up the metatypes part of the language, in a similar way we discussed in the linked thread about generics UI. If that gives us even more expressiveness for free, even better.

---

<div class="post-metadata">

**Author:** ![michelf](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/michelf/32/1180_2.png) [@michelf](https://forums.swift.org/u/michelf)\
**Post date:** [June 9, 2019, 12:27am UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/3 "2019-06-09T00:27:44Z")

</div>

I'll admit I was a little baffled yesterday by `StaticMember` when looking at the SwiftUI API. In my mind, if something needs language hacks to work, that reflects poorly on the language or the API. Even the documentation page trying to explain `StaticMember` makes it look like an obscure magic incantation.

I think I get how `StaticMember` works now, but learning this feels similar to learning [`std::enable_if`](https://en.cppreference.com/w/cpp/types/enable_if) in C++. In both cases I can recognize the cleverness and the usefulness, but it's an absolute disaster for understandability of the APIs it touches.

If we're serious about this, it should be made a feature of the language.

---

<div class="post-metadata">

**Author:** ![Davide\_Mendolia](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/davide_mendolia/32/7355_2.png) [@Davide\_Mendolia](https://forums.swift.org/u/Davide_Mendolia)\
**Post date:** [June 12, 2019, 2:00pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/4 "2019-06-12T14:00:02Z")

</div>

Why @John_McCall, @Douglas_Gregor or @Joe_Groff are not reacting to this?  
Do StaticMember are internally assumed that they will be part of SwiftUI framework and out of the scope of something that should be addressed for Swift 5.1?  
Or is it something worth addressing post swift 5.1?

---

<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:** [June 15, 2019, 10:36pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/5 "2019-06-15T22:36:17Z")

</div>

I hate to bump my own thread, but I would really appreciate it if someone from Apple could comment on this pitch. Is this something that might be viable or should I move ahead with a proposal to move `StaticMember` into the standard library? I really don't think `StaticMember` belongs in a UI framework.

---

<div class="post-metadata">

**Author:** ![filiplazov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/filiplazov/32/7886_2.png) [@filiplazov](https://forums.swift.org/u/filiplazov)\
**Post date:** [June 16, 2019, 8:23pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/6 "2019-06-16T20:23:26Z")

</div>

If nothing else you alleviated my confusion with StaticMember. I am following this pitch for sure.

---

<div class="post-metadata">

**Author:** ![woolsweater](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/woolsweater/32/2402_2.png) [@woolsweater](https://forums.swift.org/u/woolsweater)\
**Post date:** [June 17, 2019, 5:26am UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/7 "2019-06-17T05:26:44Z")

</div>

Could you provide a sample of the difference between extending the metatype and extending the existential with a static property?

```swift
extension meta ColorStyle {
    static var red: RedStyle { .init() }
}

```

vs.

```swift
extension any ColorStyle {
    static var red: RedStyle { .init() }
}

```

It's sort of unclear to me why the `static` keyword would be needed in the first case. Are these equivalent (and if so, do we need both)? Or would the latter be disallowed maybe?

---

<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:** [June 17, 2019, 6:11am UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/8 "2019-06-17T06:11:37Z")

</div>

If the first extension had `static` then you're creating an instance member on the metatypes metatype.

```swift
protocol ColorStyle {
  metatype Protocol {
    metatype Type {
      var red: RedStyle { get }
    }
  }
}

```

You can access the value though `ColorStyle.Protocol.self.red`.

* * *

The second extension adds the property to the metatype of any type that conforms to `ColorStyle`.

```swift
protocol ColorStyle {}

struct S: ColorStyle {
  metatype Type {
     var red: RedStyle { get }
  }
}

```

You can access the value through `S.self.red`.

* * *

In short there is a difference where the extension will live as an instance member, if you add or omit `static` it will alter the final destination.

```swift
extension meta T {}
// is the same as for non-protocol types
extension S.Type {} 
// or like this for protocols
extension P.Protocol {}

```

The good thing about `meta T` is that it would hide the difference between `.Type` and `.Protocol`.

* * *

Please note that `metatype` keyword does not exist in Swift nor is the above valid Swift code, but you can imagine that Swift is creating some metatypes like this and simply nest them.

---

<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:** [June 17, 2019, 6:23am UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/9 "2019-06-17T06:23:54Z")

</div>

@anandabits you may need to re-check your example in the proposed solution. The usage of `static` always nests the member further down into a metatype implicitly.

Is far as I'm concerned, the following code sample won't work with the extension from original post:

```swift
extension View {
    func colorStyle<S : ColorStyle>(_ style: S) -> some View {
        ...
    }
}

MyView().colorStyle(.red)
MyView().colorStyle(.blue)

```

For that to work you need an extension that looks more like this:

```swift
extension ColorStyle {
  static var red: RedStyle { return .init() }
  static var blue: BlueStyle { return .init() }
}

// or
extension<T: ColorStyle> meta T {
  var red: RedStyle { return .init() }
  var blue: BlueStyle { return .init() }
}

// or
extension<T: ColorStyle> T {
  static var red: RedStyle { return .init() }
  static var blue: BlueStyle { return .init() }
}

```

---

<div class="post-metadata">

**Author:** ![woolsweater](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/woolsweater/32/2402_2.png) [@woolsweater](https://forums.swift.org/u/woolsweater)\
**Post date:** [June 17, 2019, 3:52pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/10 "2019-06-17T15:52:29Z")

</div>

> [@DevAndArtist](#):
>
> If the first extension had `static` then you're creating an instance member on the metatypes metatype.

Well, I guess this is my question, because the example in the OP (which I just copied in my post) uses `static`, but the member is on the metatype, not the metatype's metatype.

---

<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:** [June 17, 2019, 3:54pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/11 "2019-06-17T15:54:00Z")

</div>

I think this is a mistake in the example in the OP.

```swift
extension meta Protocol {
  var property: SomeType { ... }
}

```

Is the correct way it should have been written.

---

<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:** [June 17, 2019, 6:13pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/12 "2019-06-17T18:13:27Z")

</div>

> [@DevAndArtist](#):
>
> I think this is a mistake in the example in the OP.
> 
> ```swift
> extension meta Protocol {
> var property: SomeType { ... }
> }
> 
> ```
> 
> Is the correct way it should have been written.

Yes, this is correct. @DevAndArtist and I discussed this in Slack and I believe with this correction he is on board with the design. @woolsweater does this correction answer your questions as well?

---

<div class="post-metadata">

**Author:** ![woolsweater](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/woolsweater/32/2402_2.png) [@woolsweater](https://forums.swift.org/u/woolsweater)\
**Post date:** [June 18, 2019, 4:59am UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/13 "2019-06-18T04:59:09Z")

</div>

I believe it does, thanks!

Edit: Oh, but does that mean `static` is _dis_allowed in an `any` extension?

---

<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:** [June 18, 2019, 7:10am UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/14 "2019-06-18T07:10:43Z")

</div>

No, if `P` is a protocol then `any P` is the protocol as type, or also known as an existential. Therefore if you extend `any P` with static member it is equivalent if you would extend `meta any P` with instance members, or in other words you‘re extending the metatype of the existential type of P. Remember that every type has a metatype, even the metatype itself (which is theoretically an infinite recursion).

```swift
extension any P { static var foo: Int { return 42 } }

extension meta (any P) {
  var foo: Int { return 42 }
}

```

* * *

And one thing that needs to be mentioned. If we would introduce `meta` keyword, there will be also `any meta T` which is an existential of the metatype. This behavior is not clear at the first glance but it would mimic the current type relationships of `.Type` metatypes.

To improve readability we could offer a type alias:

```swift
typealias Meta<T> = meta T

```

Then something like `any Meta<any P>` is more readable then `any meta any P`.

---

<div class="post-metadata">

**Author:** ![MutatingFunk](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mutatingfunk/32/984_2.png) [@MutatingFunk](https://forums.swift.org/u/MutatingFunk)\
**Post date:** [July 16, 2019, 1:05pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/15 "2019-07-16T13:05:01Z")

</div>

Just stumbled across this type in SwiftUI. Did a proposal come of this?

General question on the existing StaticMember: Is this type special-cased in the language (despite being in SwiftUI), or this a workaround anyone can use (as this thread suggests)?

Edit: I missed that the receiving method has to take S.Member, not S itself, so this isn't actually adding static members.

---

<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:** [July 16, 2019, 3:56pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/16 "2019-07-16T15:56:01Z")

</div>

> [@MutatingFunk](#):
>
> General question on the existing StaticMember: Is this type special-cased in the language (despite being in SwiftUI), or this a workaround anyone can use (as this thread suggests)?

This is a technique anyone can use. I posted some code showing how to do this in [the previous thread](https://forums.swift.org/t/make-dot-shorthand-work-with-generics-and-existentials/19324) on this topic.

---

<div class="post-metadata">

**Author:** ![Jon\_Shier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jon_shier/32/921_2.png) [@Jon\_Shier](https://forums.swift.org/u/Jon_Shier)\
**Post date:** [July 30, 2019, 5:59pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/17 "2019-07-30T17:59:32Z")

</div>

Looks like `StaticMember` has been removed in beta 5, leading to rather gross style regressions like:

```swift
.pickerStyle(.wheel) to .pickerStyle(WheelPickerStyle())

```

Removal in order to adopt a future language feature?

---

<div class="post-metadata">

**Author:** ![Jean-Daniel](https://avatars.discourse-cdn.com/v4/letter/j/977dab/32.png) [@Jean-Daniel](https://forums.swift.org/u/Jean-Daniel)\
**Post date:** [July 30, 2019, 6:09pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/18 "2019-07-30T18:09:56Z")

</div>

I'm not fond either of this change, but this is not the biggest style regression in SwiftUI Beta 5. The removal of conditional conformances on `Binding` is far more complex to workaround if you were using it.

With so much breaking changes introduced by this new beta (removal of BindableObject for instance), I wonder why we even suggest at some point that we should keep the '$' prefix in property specifier to avoid breaking WWDC material ;-)

---

<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:** [July 30, 2019, 6:15pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/19 "2019-07-30T18:15:35Z")

</div>

> [@Jean-Daniel](#):
>
> The removal of conditional conformances on `Binding` is far more complex to workaround if you were using it.

But I think they are gone for good because the `setter` part of those was far from intuitive.

For example this is the way they behaved in SwiftUI (this is custom re-implementation!!!).

```swift
extension Binding where Value: SetAlgebra, Value.Element: Hashable {
  public func contains(_ element: Value.Element) -> Binding<Bool> {
    return Binding<Bool>(
      getValue: {
        self.wrappedValue.contains(element)
      },
      setValue: { shouldContain in
        if shouldContain {
          self.wrappedValue.insert(element)
        } else {
          self.wrappedValue.remove(element)
        }
      }
    )
  }
}

extension Binding where Value: RawRepresentable {
  public var rawValue: Binding<Value.RawValue> {
    return Binding<Value.RawValue>(
      getValue: {
        self.wrappedValue.rawValue
      },
      setValue: { rawValue in
        if let newValue = Value(rawValue: rawValue) {
          self.wrappedValue = newValue
        } else {
          fatalError("cannot construct \(Value.self) using `\(rawValue)`")
        }
      }
    )
  }
}

extension Binding where Value: CaseIterable, Value: Equatable {
  public var caseIndex: Binding<Value.AllCases.Index> {
    return Binding<Value.AllCases.Index>(
      getValue: {
        let value = self.wrappedValue
        if let index = Value.allCases.firstIndex(of: value) {
          return index
        } else {
          fatalError("allCases does not contain `\(value)`")
        }
      },
      setValue: { index in
        if Value.allCases.indices.contains(index) {
          self.wrappedValue = Value.allCases[index]
        } else {
          fatalError("index out of bounce for \(Value.allCases)")
        }
      }
    )
  }
}

```

---

<div class="post-metadata">

**Author:** ![Alejandro\_Martinez](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alejandro_martinez/32/821_2.png) [@Alejandro\_Martinez](https://forums.swift.org/u/Alejandro_Martinez)\
**Post date:** [July 31, 2019, 9:45pm UTC](https://forums.swift.org/t/protocol-metatype-extensions-to-better-support-swiftui/25469/20 "2019-07-31T21:45:09Z")

</div>

Getting rid of this on SwiftUI makes it way more understandable now. It’s way easier to know what a style is now than before, and creating custom styles doesn’t need weird workarounds.  
That said, I still would love a language feature that gave us back the dot syntax in a more natural way.
