So let's say I want to implement a property wrapper which operates on either Bool or Bool?. For instance, something like this:
@propertyWrapper
struct BoolWrapper<Value: Some constraint here?> {
var wrappedValue: Value
...
}
So that it can be used in either of these ways:
@BoolWrapper var foo: Bool = true
@BoolWrapper var bar: Bool? = nil
But not with any type which is not Bool or Bool?
Is there any way to express this?
Yes.
Start from the beginning: the only expressible constraints for generic types in Swift are protocol conformances, subclassing, and combination of those:
struct MyGenericType<T: SomeProtocol> { ... }
struct MyGenericType<T: SomeClass> { ... }
struct MyGenericType<T: SomeClass & SomeProtocol> { ... }
Bool and Bool? are not related in any way by subclassing. The only remaining solution is thus protocol conformance.
So let's define a protocol that only Bool and Bool? conform to!
protocol Boolish { /* any useful common methods here */ }
extension Bool: Boolish { }
extension Optional: Boolish where Wrapped == Bool { }
@propertyWrapper
struct BoolWrapper<Value: Boolish> {
var wrappedValue: Value
}
struct Container {
@BoolWrapper var foo: Bool = true
@BoolWrapper var bar: Bool? = nil
// Error: Referencing initializer 'init(wrappedValue:)' on 'BoolWrapper'
// requires that 'String' conform to 'Boolish'
// @BoolWrapper var baz: String = ""
}
Swift won't let you restrict Boolish conformance on Bool and Bool? only, though. You may have to explicitly document that no other types should adopt this protocol.
1 Like
anandabits
(Matthew Johnson)
3
For now. My pitch for generalized supertype constraints was well received. We just can't move it forward until somebody volunteers to work on implementation. If / when that happens the compiler would recognize the Bool: Bool? relationship in a generic constraint.
Also for now. Hopefully we can express closed protocols in the language eventually. This has been the topic of several threads in the past.
1 Like
Yes. The question was framed against the current state of the language, so I did not think it was useful to raise the complexity of the answer, and transform curiosity into mourning of unborn futures. Today I believe my answer is correct, complete, and actionable.
anandabits
(Matthew Johnson)
5
Absolutely. I just wanted to add the context that there may be other options in the future.