Last active
April 12, 2020 19:33
-
-
Save ChrisMarshallNY/99fd5459e5c02f21e38b4a4c858becb2 to your computer and use it in GitHub Desktop.
This demonstrates an issue with default protocol implementations, in Swift.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is the little demo, at the start. | |
protocol A { | |
var thisIsRequired: String { get } | |
var thisIsOptional: String { get } | |
} | |
extension A { | |
var thisIsOptional: String { get { "" } set {} } | |
} | |
struct conformsToA: A { | |
var thisIsRequired: String { "Struct conformsToA" } | |
} | |
// In the first protocol, we don't use a default implementation (required conformance). | |
protocol PA { | |
var myName: String { get } | |
} | |
struct SA: PA { | |
var myName: String = "Struct A" | |
} | |
class CA: PA { | |
var myName: String = "Class A" | |
} | |
class CB: CA { | |
override var myName: String { get { "Class B" } set { } } | |
} | |
// In the second protocol, we add a default implementation (optional conformance). | |
protocol PB: PA { } | |
extension PB { | |
var myName: String { "Protocol B" } | |
} | |
// This will "fall back" to the default implementation. | |
struct SB: PB { } | |
struct SC: PB { | |
var myName: String = "Struct C" | |
} | |
// This will "fall back" to the default implementation. | |
class CC: PB { } | |
class CD: CC { | |
var myName: String = "Class D" | |
} | |
class CE: CD { | |
override var myName: String { get { "Class E" } set { } } | |
} | |
class CF: PB { | |
var myName: String = "Class F" | |
} | |
class CG: CF { | |
override var myName: String { get { "Class G" } set { } } | |
} | |
let structInstanceSA = SA() | |
let classInstanceCA = CA() | |
let classInstanceCB = CB() | |
// Part one is all about the required conformance protocol. | |
print("PART ONE") | |
print("\tDirect Print:") | |
print("\t\tStruct A: \(structInstanceSA.myName)") | |
print("\t\tClass A: \(classInstanceCA.myName)") | |
print("\t\tClass B: \(classInstanceCB.myName)") | |
func printAsProtoclA(_ inItem: PA) -> String { inItem.myName } | |
print("\tprintAsProtoclA(_: PA):") | |
print("\t\tStruct A: \(printAsProtoclA(structInstanceSA))") | |
print("\t\tClass A: \(printAsProtoclA(classInstanceCA))") | |
print("\t\tClass B: \(printAsProtoclA(classInstanceCB))") | |
func printAsStructA(_ inItem: SA) -> String { inItem.myName } | |
print("\tprintAsStructA(_: SA):") | |
print("\t\tStruct A: \(printAsStructA(structInstanceSA))") | |
func printAsClassA(_ inItem: CA) -> String { inItem.myName } | |
print("\tprintAsClassA(_: SA):") | |
print("\t\tClass A: \(printAsClassA(classInstanceCA))") | |
print("\t\tClass B: \(printAsClassA(classInstanceCB))") | |
let structInstanceSB = SB() | |
let structInstanceSC = SC() | |
let classInstanceCC = CC() | |
let classInstanceCD = CD() | |
let classInstanceCE = CE() | |
let classInstanceCF = CF() | |
let classInstanceCG = CG() | |
// Part two is where things get interesting. | |
print("PART TWO") | |
print("\tDirect Print:") | |
print("\t\tStruct B: \(structInstanceSB.myName)") | |
print("\t\tStruct C: \(structInstanceSC.myName)") | |
print("\t\tClass C: \(classInstanceCC.myName)") | |
print("\t\tClass D: \(classInstanceCD.myName)") | |
print("\t\tClass E: \(classInstanceCE.myName)") | |
print("\t\tClass F: \(classInstanceCF.myName)") | |
print("\t\tClass G: \(classInstanceCG.myName)") | |
func printAsProtoclB(_ inItem: PB) -> String { inItem.myName } | |
print("\tprintAsProtoclA(_: PA):") | |
print("\t\tStruct B: \(printAsProtoclA(structInstanceSB))") | |
print("\t\tStruct C: \(printAsProtoclA(structInstanceSC))") | |
print("\t\tClass C: \(printAsProtoclA(classInstanceCC))") | |
print("\t\tClass D: \(printAsProtoclA(classInstanceCD))") | |
print("\t\tClass E: \(printAsProtoclA(classInstanceCE))") | |
print("\t\tClass F: \(printAsProtoclA(classInstanceCF))") | |
print("\t\tClass G: \(printAsProtoclA(classInstanceCG))") | |
print("\tprintAsProtoclB(_: PB):") | |
print("\t\tStruct B: \(printAsProtoclA(structInstanceSB))") | |
print("\t\tStruct C: \(printAsProtoclA(structInstanceSC))") | |
print("\t\tClass C: \(printAsProtoclA(classInstanceCC))") | |
print("\t\tClass D: \(printAsProtoclA(classInstanceCD))") | |
print("\t\tClass E: \(printAsProtoclA(classInstanceCE))") | |
print("\t\tClass F: \(printAsProtoclA(classInstanceCF))") | |
print("\t\tClass G: \(printAsProtoclA(classInstanceCG))") | |
func printAsStructB(_ inItem: SB) -> String { inItem.myName } | |
print("\tprintAsStructB(_: SB):") | |
print("\t\tStruct B: \(printAsStructB(structInstanceSB))") | |
func printAsStructC(_ inItem: SC) -> String { inItem.myName } | |
print("\tprintAsStructC(_: SC):") | |
print("\t\tStruct C: \(printAsStructC(structInstanceSC))") | |
func printAsClassC(_ inItem: CC) -> String { inItem.myName } | |
print("\tprintAsClassC(_: CC):") | |
print("\t\tClass C: \(printAsClassC(classInstanceCC))") | |
print("\t\tClass D: \(printAsClassC(classInstanceCD))") | |
print("\t\tClass E: \(printAsClassC(classInstanceCE))") | |
func printAsClassD(_ inItem: CD) -> String { inItem.myName } | |
print("\tprintAsClassD(_: CD):") | |
print("\t\tClass D: \(printAsClassD(classInstanceCD))") | |
print("\t\tClass E: \(printAsClassD(classInstanceCE))") | |
func printAsClassF(_ inItem: CF) -> String { inItem.myName } | |
print("\tprintAsClassF(_: SF):") | |
print("\t\tClass F: \(printAsClassF(classInstanceCF))") | |
print("\t\tClass G: \(printAsClassF(classInstanceCG))") | |
// In a perfect world, this would be a syntax error: | |
let name = classInstanceCC.myName |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment