I love the idea of protocol oriented programming. So far, I’ve used it in a limited way. But, while branching out I ran in to this case that has so far forced me to use more boiler plate code than I think I should (guard statements and casting of properties)
I’m looking to understand why the type system doesn’t simply recognize that a property type conforms to a protocol, and this should allow the class to conform to a protocol. I know. That made no sense.
But, this will. Here are 2 protocols.
// // This Protocol defines a property that is required protocol ProtocolReqiuringSomePropertyType { var somePropertyRequiredByTheProtocol: Int {get} } // This Protocol defines a property that must conform to the // protocol defined above protocol ProtocolUsingPropertyOfOtherProtocolType { var someProperty: ProtocolReqiuringSomePropertyType {get set} } // This extention on the 2nd protocol accesses the // property from the first protocol extension ProtocolUsingPropertyOfOtherProtocolType { func processSomePropertyOfThePorotcol(multiplier: Int) -> Int { return someProperty.somePropertyRequiredByTheProtocol * multiplier } }
Take a look at how I use the protocols in the objects below.
// // This struct conforms to the 1st protocol. // It has the required property and defines it's own property. struct SomeStruct: ProtocolReqiuringSomePropertyType { var somePropertyRequiredByTheProtocol = 0 var somePropertyOnTheStruct: Int = 10 } // This class conforms to the 2nd protocol define above. class SomeClass: ProtocolUsingPropertyOfOtherProtocolType { // I want to define this property as type "SomeStruct". // 'SomeStruct' conforms to 'ProtocolReqiuringSomePropertyType' // I expected the type system to recognize this and allow it to be // 'SomeStruct'. But, it requires the property to be // 'ProtocolReqiuringSomePropertyType' // Does NOT compile. // var someProperty: SomeStruct = SomeStruct() // Does compile. var someProperty: ProtocolReqiuringSomePropertyType = SomeStruct() func funcThatShowsTheProblem() -> Int { // Because I have to define 'someProperty' as type // 'ProtocolReqiuringSomePropertyType', I now have to cast the property to // 'SomeStruct' to access the property defined in the struct. // Does NOT compile. // return self.someProperty.somePropertyOnTheStruct // Does compile. guard let castProperty = someProperty as? SomeStruct else { return 0 } return castProperty.somePropertyOnTheStruct } }
In SomeClass, I want to declare the property someProperty as type SomeStruct. SomeStruct conforms to ProtocolReqiuringSomePropertyType. I would expect the type system to recognize this. That should satisfy the class conformance to ProtocolUsingPropertyOfOtherProtocolType.
But, the type system is forcing me to declare someProperty as ProtocolReqiuringSomePropertyType. And that means I need to case the property to a type SomeStruct each time I want to access the property defined in the struct.
Am I missing a way to do this that doesn’t require casting SomeStruct each time?
Update
Thank you to Ash Furrow (@ashfurrow) for the work around. It’s not my ideal for how swift would handle it, but it gets the job done.
@BrianCYoung @NatashaTheRobot this _kind of_ illustrates what I mean: pic.twitter.com/YoCZxythE9
— Ash Furrow (@ashfurrow) May 16, 2016
note: I still had to cast the computed property to the backing property to compile. But, at least this is only in a single location and not everytime I want to refer to someProperty.
// class SomeClass: ProtocolUsingPropertyOfOtherProtocolType { var _someProperty = SomeStruct() var someProperty: ProtocolReqiuringSomePropertyType { get { return _someProperty } set(newValue) { guard let castValue = newValue as? SomeStruct else { assertionFailure("someProperty must be of type SomeStruct") return} _someProperty = castValue } } func FuncThatShowsTheProblem() -> Int { return self._someProperty.somePropertyOnTheStruct } }
Update Too
There is nothing like a good sleep and a long drive to let the mind wander. In this case, my mind wandered to another weak spot of my swift knowledge. Generics, AssociatedTypes and the where clause. This compiles and looks much better.
// // This Protocol defines a property that is required protocol ProtocolReqiuringSomePropertyType { var somePropertyRequiredByTheProtocol: Int {get} } // This Protocol defines a property that must conform to the // protocol defined above protocol ProtocolUsingPropertyOfOtherProtocolType { associatedtype T var someProperty: T {get set} } // This extention on the 2nd protocol accesses the // property from the first protocol extension ProtocolUsingPropertyOfOtherProtocolType where T: ProtocolReqiuringSomePropertyType { func processSomePropertyOfThePorotcol(multiplier: Int) -> Int { return someProperty.somePropertyRequiredByTheProtocol * multiplier } } // This struct conforms to the 1st protocol. // It has the required property and defines it's own property. struct SomeStruct: ProtocolReqiuringSomePropertyType { var somePropertyRequiredByTheProtocol = 0 var somePropertyOnTheStruct: Int = 10 } // This class conforms to the 2nd protocol define above. class SomeClass: ProtocolUsingPropertyOfOtherProtocolType { var someProperty: SomeStruct = SomeStruct() func FuncThatShowsTheProblem() -> Int { return self.someProperty.somePropertyOnTheStruct } }
1 comment
Comment by Kevil Tuan
Kevil Tuan September 28, 2018 at 2:47 pm
Thank you for sharing download bee talk