Joe, was there an off-list email? I don't see your comments in my mail client 
or on Mailman, only quoted by Brent.

On Mar 14, 2016, at 7:59 PM, Brent Royal-Gordon via swift-evolution 
<[email protected]> wrote:

>> Do you have an imagined use for throwing getters?
> 
> In the proposal, I cite a pair of framework methods that I think would be 
> better modeled as a throwing subscript:
> 
>    class NSURL {
>        func getResourceValue(_ value: 
> AutoreleasingUnsafeMutablePointer<AnyObject?>, forKey key: String) throws
>        func setResourceValue(_ value: AnyObject?, forKey key: String) throws
>    }
> 
> Here's another, much less matter-of-opinion usage:
> 
>      // Numeric types, Bool, String, JSONValue?, [JSONValue], and [String: 
> JSONValue] conform.
>    protocol JSONValue { ... }
>    
>    protocol JSONRepresentable {
>        associatedtype JSONRepresentation: JSONValue
>        
>        init(json: JSONRepresentation) throws
>        var json: JSONRepresentation { get throws }
>    }
>    
>    struct User: JSONRepresentable {
>        var json: [String: JSONValue]
>        
>        var friends: [User] {
>            get throws {
>                guard let friendsJSON = json["friends"] as? 
> [User.JSONRepresentation] else {
>                    throw UserError.InvalidFriends
>                }
>                return friendsJSON.map { try User(json: $0) } 
>            }
>            set throws {
>                json["friends"] = newValue.map { try $0.json }
>            }
>        }
>    }
> 
> As long as we're doing computation in getters, it will make sense for that 
> computation to raise errors. I don't think we can get around the need for 
> `get throws`.
> 
>> Allowing the getter or setter to throw independently greatly complicates the 
>> abstract model for properties. While we don't have much in the way of 
>> abstraction tools over properties yet, it would be important to consider the 
>> impact this might have on "lens" functions that can perform mutable 
>> projections. Right now, you can more or less categorize mutable properties 
>> into two groups:
>> 
>> - "reference-like", projecting mutable storage indirectly through a 
>> reference, which you could think of as having a type (Base) -> inout 
>> Property. This includes not only class properties but `nonmutating` struct 
>> properties like `UnsafeMutablePointer.memory`.
>> - "value-like", projecting mutable storage that is part of a larger mutable 
>> value, which you could think of as having type (inout Base) -> inout 
>> Property. This includes most mutable struct properties that aren't 
>> explicitly `nonmutating`.
> 
> I think you may be overoptimistic here—I've tried to prototype lenses before 
> (using protocols and classes) and I've always quickly ended up in 
> combinatorial explosion territory even when merely modeling existing 
> behavior. First of all, mutability is uglier than you imply:
> 
> - There's actually a third setter category: read-only. 
> - The getter and setter can be *independently* mutating—Swift is happy to 
> accept `mutating get nonmutating set` (although I can't imagine why you would 
> need it).
> 
> So that's already six, not two, categories.
> 
> Another complication comes from the type of the property in the lens's view. 
> You need Any-typed lenses for KVC-style metaprogramming, but you also want 
> type-specialized lenses for greater safety where you have stronger type 
> guarantees. And yet their setters are different: Any setters need to be able 
> to signal that they couldn't downcast to the concrete type of the property 
> you were mutating. (This problem can actually go away if you have throwing 
> setters, though—an Any lens just has to make nonthrowing setters into 
> throwing ones!)
> 
> (For added fun: you can't model the relationship between an Any lens and a 
> specialized lens purely in protocols, because that would require support for 
> higher-kinded types.)
> 
> So if you want to model the full richness of property semantics through their 
> lenses, the lens system will inevitably be complicated. If you're willing to 
> give up some fidelity when you convert to lenses, well, you can give up 
> fidelity on throwing semantics too, and have the lens throw if either 
> accessor throws.
> 
>> If properties can throw, we'd want to be able to represent that in the type 
>> system for projection functions. If there are four different ways a property 
>> can throw (no throws, only reads can throw, only writes can throw, or both 
>> reads and writes can throw), that gets really complicated.
> 
> Nevertheless, this might be a good enough reason to invoke the escape hatch I 
> left in the Alternatives Considered section:
> 
>    Calling a setter often implicitly involves calling a getter, so it may 
>    make sense to require the setter to be at least as throwing as the 
>    getter. Absent feedback to this effect from implementors, however, my 
>    instinct is to leave them independent…
> 
> The way I see it, we have three options for the throwing variants we might 
> allow:
> 
> - Independent: Any combination
> - Dependent: Getter can't throw unless setter can (no "get throws set")
> - Setter only: Getter can't throw (no "get throws set" or "get throws set 
> throws")
> 
> We also might want to look at that weird nonmutating case, so there are two 
> options there:
> 
> - Independent: Any combination
> - Dependent: Getter can't mutate unless setter can (no "nonmutating get 
> mutating set")
> 
> (If we really wanted to, we could probably make the `mutating` property 
> setter-only; things like `lazy` would just have to use a reference-typed box. 
> That would be a pretty violent change to the language, though.)
> 
> That's a lot of possible semantics, so I wrote a script to help me understand 
> what each policy would do. Here's the abridged results:
> 
>    20 variants for independent mutating, independent throws
>    16 variants for independent mutating, dependent throws
>    16 variants for dependent mutating, independent throws
>    13 variants for dependent mutating, dependent throws
>    12 variants for independent mutating, setter-only throws
>    10 variants for dependent mutating, setter-only throws
> 
> (Full results, plus script: 
> <https://gist.github.com/brentdax/97e3dfe7af208da51a1a>. By the way, without 
> any `throws` support at all, independent mutating requires 6 variants and 
> dependent mutating requires 5.)
> 
> My main conclusion is that limiting `throws` to setters only doesn't actually 
> gain us much over limiting both `throws` and `mutating` to the "sensible" 
> combinations.
> 
> And again, this only applies if we want lenses to model all property 
> semantics with complete fidelity. We could offer fewer lenses if we're 
> willing to accept clunkier interfaces. Heck, we could offer a single lens 
> type if we're okay with dynamic safety:
> 
>    // Semantics would be equivalent to:
>    struct Lens<Instance, Value> {
>        // Can throw only errors thrown by the property.
>        func value(for instance: inout Instance) throws -> Value
> 
>        // Can throw `SetterInaccessible` or errors thrown by the property.
>        func updateValue<T>(for instance: inout Instance, mutator: (inout 
> Value) -> T) throws -> T
>        
>        // Can throw `RequiresMutating` or errors thrown by the property.
>        func value(for instance: Instance) throws -> Value
>        
>        // Can throw `SetterInaccessible`, `RequiresMutating`, or errors 
> thrown by the property.
>        func updateValue<T>(for instance: Instance, mutator: (inout Value) -> 
> T) throws -> T
>    }
>    extension Lens {
>        // `updateValue` methods can also throw `InvalidValueType`.
>        init<ConcreteValue: Value>(downcasting: Lens<Instance, ConcreteValue>)
>    }
>    enum LensError: Error {
>        case InvalidValueType (expectedType: Any.Type, foundType: Any.Type)
>        case SetterInaccessible
>        case RequiresMutating
>    }
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to