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