1

I am wishing to implement a pattern similar to Notification.Name where anyone can add one later via an extension, like this:

Swift 4

public protocol Foo {
    var bar: String { get }
}



public struct FooImpl: Foo {
    public let bar: String
}



public extension Foo {
    public static let baz: Foo = FooImpl(bar: "baz")
}

// Ideal usage:
someFuncThatTakesAFoo(.baz)

This seems fine to me, but I get a confusing error when compiling:

/path/to/main.swift:24:23: error: static stored properties not supported in generic types
    public static let baz: Foo = FooImpl(bar: "baz")
           ~~~~~~     ^

What's going on here, and what's a solution?

Ky -
  • 30,724
  • 51
  • 192
  • 308
  • 1
    Compare: [Extension may not contain stored property but why is static allowed](https://stackoverflow.com/q/45467329/2976878). I do agree the diagnostic isn't great in this case. – Hamish Sep 06 '17 at 22:29
  • Related Swift bug: [SR-5856](https://bugs.swift.org/browse/SR-5856) – Ky - Oct 17 '17 at 16:55

1 Answers1

0

That is a weird error message, but your code shouldn't compile anyways. Stored properties are not supported in extensions, hence the error.

By removing the static keyword and just leaving baz as a stored property, you get a meaningful error:

extensions may not contain stored properties

Changing the declaration to a computed property (and hence declaring it mutable) the error magically disappears.

public protocol Foo {
    var bar: String { get }
}

public struct FooImpl: Foo {
    public let bar: String
}


public extension Foo {
    public static var baz: Foo {
        return FooImpl(bar: "baz")
    }
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • But this works just fine: `extension FooImpl { static let baz = FooImpl(bar: "baz") }`. Like I said, this is a common practice in Swift, notably used in `Notification.Name` to allow semantic creation and use of object instances with the dot-prefix syntax – Ky - Sep 06 '17 at 20:40
  • Also, when I try to use this solution like `let x = Foo.baz`, I get a new confusing error: `Static member 'baz' cannot be used on protocol metatype 'Foo.Protocol'` – Ky - Sep 06 '17 at 20:43
  • [Here](http://swift.sandbox.bluemix.net/#/repl/59b063c0d52b657e47709c8b) you can actually try running the code, it compiled with no problem. Also have a look at [this](https://stackoverflow.com/a/38885813/4667835) answer, which also explains that you cannot have stored properties in protocol extensions. Moreover, the example in your comment is not the same as the one in the question, the comment one is a struct extension, while the question one is a protocol extension. – Dávid Pásztor Sep 06 '17 at 21:11
  • The error I described is there: http://swift.sandbox.bluemix.net/#/repl/59b153ef0e5da9521fbd03df – Ky - Sep 07 '17 at 14:13
  • Well, that shouldn't work. A protocol on its own doesn't exist. `let x = FooImpl.baz` is valid, `let Foo.baz` is not. – Dávid Pásztor Sep 07 '17 at 14:15
  • A protocol doesn't exist? I'm not sure what you're saying. Also the example in my comment is the usage site of the problem in my question. I'll edit it to reflect that. – Ky - Sep 07 '17 at 14:24
  • A protocol is an abstract type. There is no such thing as an instance of a protocol and hence your code cannot compile. You can implement classes that conform to the protocol and those classes can have instances and hence access functions/computed properties that are part of the protocol. Have a look into protocols in Swift, it seems you have a big misunderstanding about what they are and how they work. – Dávid Pásztor Sep 07 '17 at 14:26
  • @DávidPástor I get what you're saying, and I agree at runtime that's true. Still, `Foo.baz` is just syntax and the compiler should be able to work out what I want to do. Perhaps it creates a new uniquely-named global variable, perhaps something I can't imagine. It just doesn't seem so unreasonable that it's still not possible in version 4.0. – Ky - Oct 17 '17 at 16:54