Static/Class stored properties in generic types?


(Jon Shier) #1

I'm attempted to create an observables system that can be updated and subscribed to generically. I use something like this:

final class Observer<Value> { }

protocol Observable {
    associated type Value
    static var observable: Observer<Value>
}

And I can use it fine with normal types:

struct Model: Observable {
    static let observable = Observer<Model>()
}

But attempting to make generic types conform:

final class Future<Value> {
    static let observable = Observer<Future<Value>>()
}

leads to a simple error: Static stored properties not supported in generic types

Is this a limitation that will be lifted eventually? Any ideas for what I can do in the meantime? Ideally, I'd like to have an API like this:

Model.observerable.observe { }
Future<Model>.observable.observe { }

Otherwise, I'm stuck creating properties for every type of generic I want to observe. Considering I'm using this for networking and other async source, that would be quite a few, so it's not really scalable without some general support. Ideas?


(Jordan Rose) #2

I think a good part of this restriction came from the fact that it's unclear whether Foo<X>.value and Foo<Y>.value share the same storage. There's actually only one answer that works, but it's still non-obvious enough that we weren't sure if it was a good idea to allow it.

On the implementation side, it's also non-trivial to implement, since new generic types can be created ad infinitum at runtime.


(Joe Groff) #3

I don't recall any discussions about whether it's a good idea to support; the lack of implementation is the only barrier I know of.


(Hamish Knight) #4

It is possible to implement static stored properties on generic types manually using a global dictionary – albeit with a bit of boilerplate, see:


(Stellar) #5

From the user's perspective, defining a static constant in a generic is a common scenario and should be well supported.


(John McCall) #6

Since globals are already lazily-initialized, I think the only question here is whether there's value in also supporting the truly-unique case — which would have to be semantically restricted to not refer to the type parameters, of course — in addition to the generic case. But I suppose it's pretty clear from precedent elsewhere that static doesn't mean the former, so yeah, it's just a matter of implementation.


(Joe Groff) #7

It seems to me we could potentially hide the true uniqueness behind the ABI (at least when it isn't exposed as a stored property with @_fixed_layout) and treat it as an optimization. If the property is a let and its initializer independent of the type context, we could collapse it into a unique variable.


(John McCall) #8

Makes sense.


(Dante Broggi) #9

Would that work for reference holding types?
That could be another limitation on the optimization.