EnvironmentKey Having an Opaque Type

Has anyone successfully defined a custom environment key with an opaque type?


Can you elaborate on what you mean by “opaque type”?

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

Hi Eskimo,

I'm using the term "opaque type" as defined here:

[https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html](http://Opaque Types)

I simplified my code to provide an example of what I'm trying to accomplish and the error the compiler is giving me. Here's the code snippet:

import SwiftUI

protocol S {}

struct SKey: EnvironmentKey {
    static var defaultValue: some S = DefaultS()

extension EnvironmentValues {
    var s: some S {
        get { self[SKey.self] }
        set { self[SKey.self] = newValue }
        //                      ^
        // Cannot assign value of type 'some S' (type of 
        // 'EnvironmentValues.s') to subscript of type 'some S' (type of 'SKey.defaultValue')

struct DefaultS: S {}

I do not understand why the compiler is indicating this error, and hoping someone can shed some light on this.

At a higher-level, I'm developing a control and want to give the caller the ability to modify the appearance of the control using a style, similar to SwiftUI's Button and ButtonStyle. If passing the style down through the view hierarchy is not allowed using an environment value, then perhaps SwiftUI is using an environment object, which I have not explored yet. However, my instinct tells me that using an environment object is probably not the right course.


How do you expect the setter to work? The caller doesn't know the type of s, only that it conforms to some protocol S. They can't possibly supply a value of the right type to the s.setter.

SE-0244 states,

With a subscript or a computed property, the type of the value provided to the setter (e.g., newValue ) is determined by the return statements in the getter, so the type is consistent and known only to the implementation of the property or subscript.

It also provides an example,

protocol P { }
private struct Impl: P { }

public struct Vendor {
  private var storage: [Impl] = [/* ... */]

  public var count: Int {
    return storage.count

  public subscript(index: Int) -> some P {
    get {
      return storage[index]
    set (newValue) {
      storage[index] = newValue

I don't see much of a difference between this example and what I'm trying to accomplish. If you do, can you please explain?


Ah right. Totally forgot it was in the proposal. I got the same error when trying to run the example in the Playground 3.3.1 and Xcode 11.7. I never used it before, so I don't know if there is a regression, or if it was never supported since the beginning.

I'm seeing the same issue using Xcode Version 12.0 beta 6 (12A8189n).

Out of curiosity, how do determine the version of Playground?

You can checked the App Store (iOS & macOS) or check the about (macOS).

If this is indeed a regression, can someone suggest a workaround?

Terms of Service

Privacy Policy

Cookie Policy