Thanks, Karl, that's great!

In the end, I think I need to use classes, because I do have reference 
semantics in my model (e.g. a part definition can be referenced by multiple 
instances).

But this helps me get my head around the techniques. Thanks!

> On Aug 1, 2016, at 21:39 , Karl <razie...@gmail.com> wrote:
> 
> A protocol can require that a certain initialiser exists, but it can’t 
> provide a default implementation (you can add initialisers in a protocol 
> extension IIRC, but then they must delegate to an actual, required 
> initialiser).
> 
> A protocol is not the same thing as a subclass. Any type could conform to a 
> protocol. In that case, your init method wouldn’t be valid - there may be 
> other stored properties besides “uuid”; in fact, “uuid” may not be a stored 
> property at all by that type. For example, I could write an extension for 
> String or Array<T> which makes them now conform to Element. The fact that 
> “uuid” isn’t declared mutable but you are trying to set it, is a sign that 
> there is not enough knowledge about the type to do this.
> 
> If you do have some common properties and want to encapsulate their logic, 
> create a struct. For example, you might create an “XMLHeader” struct, and 
> PartDefinition and PartInstance can contain it by composition. You would need 
> to add forwarding accessors, but they can be added in an extension to avoid 
> cluttering your code.
> 
> e.g.:
> 
>> // Could this even be a nested type inside XMLElement, perhaps? That would 
>> be even cleaner. Maybe there could then be a “var header: Header?" computed 
>> property on XMLElement?
>> 
>> struct XMLElementHeader {
>>      let uuid : UUID
>>      var name : String?
>>      var desc : String?
>> 
>>      static func parse(_ xml: XMLElement) -> XMLElementHeader? {
>>              // Validate xml
>>              return XMLElementHeader(uuid: ..., name: .none, desc: .none)
>>      }
>> }
>> 
>> class PartInstance {
>> 
>>      var header : XMLElementHeader
>> 
>>      init(xml: XMLElement) {
>>              guard let parsedHeader = XMLElementHeader.parse(xml) else { 
>> fatalError() }
>>              header = parsedHeader
>>      }
>> }
>> 
>> class PartDefinition {
>>      
>>      var header : XMLElementHeader
>> 
>>      init(xml: XMLElement) {
>>              guard let parsedHeader = XMLElementHeader.parse(xml) else { 
>> fatalError() }
>>              header = parsedHeader
>>      }
>> }
> 
> Then, if you want to provide a nicer interface, do it with an extension:
> 
>> protocol Element {
>>      var uuid : UUID    { get }
>>      var name : String? { get, set }
>> }
>> 
>> extension PartInstance : Element {
>>      var uuid : UUID    { return header.uuid }
>>      var name : String? { get { return header.name }
>>                                               set { header.name = newValue } 
>> }       
>> }
> 
> That’s how I would do it, anyway.
> 
> Karl
> 
> 
>> On 1 Aug 2016, at 22:32, Rick Mann via swift-users <swift-users@swift.org> 
>> wrote:
>> 
>> In my schematic capture app, I had a class hierarchy that started with 
>> Element. From that I derived PartDefinition and PartInstance. Element has an 
>> immutable UUID, name, and description. Element knows how to encode itself as 
>> XML by conforming to an XMLCoding protocol.
>> 
>> Now I'm trying to make Element into a Protocol, and make PartDefinition and 
>> PartInstance into structs. But I can't quite figure out how to inherit the 
>> XMLCoding implementation for Element. That is, Element can encode/decode its 
>> UUID, name, and desc. It does the decode in a convenience init(xml:) method 
>> that takes an XMLNode to parse.
>> 
>> So how to I add another init(xml:) method to one of my structs (like 
>> PartDefinition), and have it call the init(xml:) method on Element? With 
>> class inheritance, I was able to do this with a call to super. It's not 
>> clear to me how to do this with Protocols.
>> 
>> It needs to be in init() because I want some of the instance variables to be 
>> let and non-optional. Not actually sure how to do this.
>> 
>> protocol Element
>> {
>>   var uuid    :      UUID { get }
>>   var name    :      String?  { get }
>>   var desc    :      String?  { get }
>> }
>> 
>> extension Element
>> {
>>   init(xml inElement: XMLElement)
>>   {
>>       self.uuid = <parse from inElement>
>>   }
>> }
>> 
>> class
>> PartInstance : Element
>> {
>>   init()
>>   {
>>       self.uuid = UUID()
>>   }
>> 
>>   init(xml inElement: XMLElement)
>>   {
>>       //  Use shared implementation in Element extension?
>>   }
>> 
>>   let uuid: UUID
>>   var name: String?
>>   var desc: String?
>> }
>> 
>> class
>> PartDefinition : Element
>> {
>>   etc...
>> }
>> 
>> I may be missing some aspect of this entirely, but I'm having a hard time 
>> seeing how to avoid lots of code duplication in this scenario. Appreciate 
>> thoughts and advice…
>> 
>> -- 
>> Rick Mann
>> rm...@latencyzero.com
>> 
>> 
>> _______________________________________________
>> swift-users mailing list
>> swift-users@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
> 


-- 
Rick Mann
rm...@latencyzero.com


_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to