I am refactoring / adding features to some code and encountered a situation where I want to migrate by protocoling the types.
Currently I have a data type like this:
struct Result {
let a: Int
let b: Int
let c: Int
}
and an ObservableObject
like this:
class Worker1 : ObservableObject {
@Published var results: [Result] // this data is rendered by the UI against the concrete type of "Result"
}
and some views similar to this (using the Result
type):
struct SomeUIComponent: View {
@Binding var results: [Result]
....
}
I am in the process of migrating to an augmented result type (identical otherwise to the original result)
struct Result2 {
let a: Int
let b: Int
let c: Int
let d: Int // this along with some additional non-trivial things are new
}
handled by a new Worker2
ObservableObject
class Worker2: ObservableObject {
@Published var results: [Result2] // I want this as a protocol instead
}
for the older UI components, they only utilize the common fields a
and b
while some new components care about the newly added fields.
I want to back patch the existing UI components gradually by working against the protocol types rather than the concrete types directly
To achieve this I created a set of protocols to align with the original Result
type and implemented it on both the original Result
as well as the newly defined Result2
:
// currently aligned with the original Result type
protocol ResultProtocol {
var a: Int {get}
var b: Int {get}
var c: Int {get}
}
I need an additional protocol to support Worker1
publishers and the new Worker2
publishing of the ResultProtocol
type (rather than the concrete type it had been defined to use earlier). This is important to allow gradual replacement of parts without fixing a large combination of things.
I tried this:
// create a supporting protocol which the UI components can access , reading the protocol stubbed type rather than the concrete type
protocol WorkerProtocol {
var resultsPublisher: Published<[ResultProtocol]>.Publisher {get}
}
and now hitting a wall when trying to extend the "Worker1" implementation to handle this:
extension Worker1 : WorkerProtocol {
var resultsPublisher: Published<[ResultProtocol]>.Publisher { $results } // this doesn't work, it doesn't "cast" the concrete type "Result" to the protocol type
// I believe the concrete type is Published<[Result]>.Publisher, while Result does implement the ResultProtocol, this doesn't compile
// Type of expression is ambiguous without more context
}
I tried to cast it / map it / erase to anytype it / etc.
example:
$results as Published<[ResultsProtocol]>.Publisher
$results.eraseToAny