I have a generic protocol:
protocol SectionType {
associatedtype I: Equatable
associatedtype T: Equatable
var info: I? { get }
var items: [T] { get }
}
and an Array extension for it:
/// Offers additional method(s) to process SectionType list.
extension Array where Element: SectionType {
/// Dummy comparision method. Implementation is not that relevant but just to employ Equatable.
/// - Parameter to: Another array of sections.
/// - Returns: True if first info and first elemements in both arrays exist and both are equal.
func dummyCompare(with otherArray: [Element]) -> Bool {
guard
let first = self.first,
let firstOther = otherArray.first,
let firstElement = first.items.first,
let firstOtherElement = firstOther.items.first,
let firstInfo = first.info, let firstOtherInfo = firstOther.info
else { return false }
return firstInfo == firstOtherInfo && firstElement == firstOtherElement
}
}
No problem when using with concrete implementations:
Example 1: Works with specific implementation with build-in String type:
Declaration:
struct StringSection: SectionType {
let info: String?
let items: [String]
}
Usage:
let stringSection1 = StringSection(info: "Info 1", items: ["Item 1", "Item 2"])
let stringSection2 = StringSection(info: "Info 2", items: ["Item 3", "Item 4"])
let stringSections1 = [stringSection1, stringSection2]
let stringSections2 = [stringSection2, stringSection1]
var areEqual = stringSections1.dummyCompare(with: stringSections2)
print("String section 1 equals 2?: \(areEqual)")
Example 2 - Works with specific implementation with custom types:
Declarations:
protocol SectionInfoType {
var title: String { get }
}
/// BTW: This is just Swift's stragne way of implementing Equatable protocol for your type:
func == (lhs: SectionInfoType, rhs: SectionInfoType) -> Bool {
return lhs.title == rhs.title
}
struct SpecificSectionInfo: SectionInfoType, Equatable {
let title: String
static func == (lhs: SpecificSectionInfo, rhs: SpecificSectionInfo) -> Bool {
return lhs.title == rhs.title
}
}
protocol SectionItemType {
var text: String { get }
}
/// BTW: This is just Swift's stragne way of implementing Equatable protocol for your type:
func == (lhs: SectionItemType, rhs: SectionItemType) -> Bool {
return lhs.text == rhs.text
}
struct SpecificSectionItem: SectionItemType, Equatable {
let text: String
static func == (lhs: SpecificSectionItem, rhs: SpecificSectionItem) -> Bool {
return lhs.text == rhs.text
}
}
struct SpecificSection: SectionType {
let info: SpecificSectionInfo?
let items: [SpecificSectionItem]
}
Usage:
let specInfo1 = SpecificSectionInfo(title: "Info 1")
let specItem1 = SpecificSectionItem(text: "Specific item 1")
let specItem2 = SpecificSectionItem(text: "Specific item 2")
let specInfo2 = SpecificSectionInfo(title: "Info 2")
let specItem3 = SpecificSectionItem(text: "Specific item 3")
let specItem4 = SpecificSectionItem(text: "Specific item 4")
let specSection1 = SpecificSection(info: specInfo1, items: [specItem1, specItem2])
let specSection2 = SpecificSection(info: specInfo2, items: [specItem3, specItem4])
let specSections1 = [specSection1, specSection2]
let specSections2 = [specSection2, specSection1]
let areEqual = specSections1.dummyCompare(with: specSections2)
print("Specific section 1 equals 2?: \(areEqual)")
So far, so good, everything works and compiles. But ... I have at least 2 problems with this approach:
Problem 1:
Just from 2 examples above, one can see that this approach needs 'specific' implementation of a SectionType protocol for every combination of info
and items
type. This seems not so efficient (tremendous amount of code for every each implementation) nor generic.
What I need is a more generalised embodiment of SectionType
protocol where types for info
and items
need to be protocols (provided from external APIs as protocols).
A perfect example (but does not compile):
struct Section: SectionType {
typealias I = SectionInfoType
typealias T = SectionItemType
let info: I?
let items: [T]
}
Problem 2:
I need to be able to pass it over to other protocol oriented API, f.ex.: as an argument to function like:
func consume(section: SectionType<SectionInfoType, SectionItemType>) {}
But above function declaration produces:
Cannot specialize non-generic type 'SectionType'
with Xcode proposing a fix: 'Delete <SectionInfoType, SectionItemType>'
resulting in this:
func consume(section: SectionType) {}
This does not compile neither and I can not find a way to make it work.
Is it possible to do or is that Swift 3 limitation (I am using Swift 3.1)?
I created Git repository demonstrating those issues. Feel free to collaborate:
https://github.com/lukaszmargielewski/swift3-learning-generics
Section
generic such as in your previous question? e.gstruct Section<InfoT: Equatable, ItemsT: Equatable> : SectionType {...}
. – Hamish==
(Equatable
overload function). Note the example from there does not actually use it. When added -it gave compilation error:SectionInfoType does not conform to the Equatable protocol
even if overload worked outsideArray
extension. That question also did not explore possibilities of specifying inferred types as protocols. – LukaszArray
extension should work fine so long as you're talking in terms ofElement.I
andElement.T
. Sounds like you're trying to treat a protocol type as a concrete type that conforms to a protocol (this isn't possible, protocols don't conform to themselves – solution is usually a type eraser). It would seem to me that would be the issue worth pursuing, rather than manually specialisingSection
. (re: downvote, not me!). – Hamish