> On Mar 14, 2016, at 4:59 PM, Brent Royal-Gordon <[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`.
It's debatable whether this is a good use of property syntax. The standard library doesn't even use property syntax for things that might unconditionally fail due to programmer error. >> 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. How is that different from a nonmutating setter? Did you mean a read-only property? A read-only property is just a regular function, Base -> Property. > - 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). Fair point. From the point of view of the property abstraction, though, `mutating get nonmutating set` is erased to `mutating get mutating set`. That leaves three kinds of mutable property projection. `mutating get` itself is sufficiently weird and limited in utility, its use cases (IMO) better handled by value types holding onto a class instance for their lazy- or cache-like storage, that it might be worth jettisoning as well. > 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!) This sounds like something generics would better model than Any polymorphism, to carry the type parameter through the context you need polymorphism. > (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. True, you could say that if either part of the access can throw, then the entire property access is abstractly considered `throws`, and that errors are checked after get, after set, and for an `inout` access, when materializeForSet is called before the formal inout access (to catch get errors), and also after the completion callback is invoked (to catch set errors). That means you have to `try` every access to an abstracted property, but that's not the end of the world. -Joe _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
