Skip to content

Instantly share code, notes, and snippets.

@ChrisMarshallNY
Last active April 12, 2020 19:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChrisMarshallNY/99fd5459e5c02f21e38b4a4c858becb2 to your computer and use it in GitHub Desktop.
Save ChrisMarshallNY/99fd5459e5c02f21e38b4a4c858becb2 to your computer and use it in GitHub Desktop.
This demonstrates an issue with default protocol implementations, in Swift.
// 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