[swift-evolution] [Review] SE-0109: Remove the Boolean protocol

David Sweeris davesweeris at mac.com
Wed Jun 29 11:40:42 CDT 2016


On Jun 29, 2016, at 8:47 AM, Matthew Johnson <matthew at anandabits.com> wrote:
> 
> On Jun 29, 2016, at 7:52 AM, David Sweeris via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
> 
>> Aside from confusing people, does it actually hurt anything? It's not too hard to imagine that someone might make a type conform to `Boolean` because, within their code, the semantics of "x || y” are clear and that reads better than "x.foo || y.foo".
>> 
>> I agree it feels out of place, though. What about renaming it to something like "CustomBooleanConvertible”?
> 
> IIRC Optional conformed to this protocol early on and that conformance was removed.  In practice the idea of a protocol for "truthiness" to which non-Boolean types conform caused more confusion than it provided value.  It was a cool idea that just didn't work out so well.
> 
> IMO if it doesn't make sense for Optional to conform it is pretty unlikely it would make sense for other types to conform.  It seems like a good idea to remove the protocol.

What if you wanted to do something like this?
class RemoteBool : Boolean {
    let url: URL
    private var cachedValue: Bool? = nil // gets updated periodically in another thread or some other async method
    init(boolURL: URL) { url = boolURL; sync_update() }
    var boolValue: Bool { return cachedValue ?? sync_update() }
    func sync_update() -> Bool {…} // synchronously sets `cachedValue` and returns the newValue
    func async_update() {…} // asynchronously sets `cachedValue`
}

Or experiment with how ternary logic interacts with boolean logic?
protocol Ternary : Boolean, BooleanLiteralConvertible, NilLiteralConvertible {
    static var forcedBoolValue: Bool { get }
    var ternValue: Bool? { get set }
    init(_: Bool?)
}
extension Ternary {
    var boolValue: Bool { return ternValue ?? Self.forcedBoolValue }
    init(booleanLiteral value: Bool) { self.init(value) }
    init(nilLiteral: ()) { self.init(nil) }
}
struct TendsTrue: Ternary {
    static let forcedBoolValue = true
    var ternValue: Bool?
    init(_ value: Bool?) { ternValue = value }
}
struct TendsFalse: Ternary {
    static let forcedBoolValue = false
    var ternValue: Bool?
    init(_ value: Bool?) { ternValue = value }
}

Yeah, sure, in either case you could go through and use extensions to add support for your custom type on an as-needed basis. Life would be way easier, though, if the standard library was simply coded to an abstracted boolean protocol. Isn’t this kind of scenario that led to Swift having generics?

Renaming `Boolean` to something that doesn’t sort next to `Bool` removes the source of confusion. And while I completely agree that the standard library should be consistent it its use of abstraction protocols vs concrete types, in this regard I think this proposal goes in the wrong direction (although, in my whatever-the-opposite-of-defense-is I’m a huge fan of having generic library code wherever possible, so maybe I’m biased).

Is there a downside to overloading any function which takes a Bool with a version that takes a “CustomBooleanConvertible”?
func foo(_ bar: Bool) {} // pretend this exists in the standard library
func foo <T: CustomBooleanConvertible> (_ bar: T) { foo(bar.boolValue) } // add this, and keep the concrete version as well, both to provide the actual implementation and to prevent the generic version from recursively calling itself

- Dave Sweeris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160629/a1e65632/attachment.html>


More information about the swift-evolution mailing list