SE-0299 Extending Static Member Lookup in Generic Contexts

Personally, I am not a fan of the whole idea based on the issue @jrose pointed out. At a conceptual level, I think, a protocol's members need to make sense for all conforming types. However, this proposal encourages code patterns which break that. Is that a serious issue? I've been trying to rack my brain, but I haven't been able to come up with compelling examples.

Moreover, if you work with classes instead of protocols, the following works today:

class C {
    static var d: D = D()
}
class D: C {}
func f<T: C>(_: T) {}
let _ = f(.d)

So, it's a bit puzzling that this doesn't work when you use value types + protocols instead of classes. :slight_smile: In that sense, I think this change makes the language more consistent [and arguably means that we should prefer this spelling in the proposal over the ones other people have suggested.]

Given that, on deeper introspection, my objections don't have compelling examples (apart from the .bitWidth one earlier in the thread, which is an unfortunate casualty), but are based more on an aesthetic judgement (I wouldn't write such code and I wouldn't want other people to write such code), I would like to withdraw my previous objections to the proposal. I think it's fine.

2 Likes

Thanks, @typesanitizer! Also note that, as you mentioned, we have exactly the same issue with classes as with protocol declarations here - static var d would be propagated to all subclasses or C so if there is no problem with that, to enable leading-dot syntax, I don't know why it should be any different for protocols.

Just to clarify, this works today because C here carries a witness for d since it's a concrete class and : C is just a subtype relation, not a conformance.

Right, I get that, but they do share some similarities in syntax and behavior (subclassing doesn't have different syntax), so I think the same syntax working for protocols makes sense. :+1:

I understand, just wanted to clarify since you mentioned that it's puzzling :slight_smile:

Just to build on @typesanitizer's point a bit further, I'll also note that the following compiles using classes, even though the equivalent construction using protocols wouldn't compile even under this proposal:

struct Other {
    var d = D()
}

class C {
    static var other = Other()
}
class D: C {}
func f<T: C>(_: T) {}
let _ = f(.other.d)
1 Like

In this example C would be picked for T and base is going to be C.Type. Protocols would have to get multiple features, including self-conformance when associated types are involved, for this to work. Once language is expended to support that it would be possible for leading-dot syntax to be consistent for both conformance and subtyping.

2 Likes

I came here to ask about this. I don't quite see how this could work without something like that being autogenerated? I mean the upper protocol declaration just says that ToggleStyle needs to have a static var that returns a member of CheckboxToggleStyle, but wouldn't there also have to be an implementation?

Thanks for participating in the review, everyone! The core team has decided to return this proposal for revision to address the problem of type namespace pollution.

1 Like