Alc
(Alc)
1
How can I have a default init(fromPath:) for all the structs that conform to a protocol?
I tried the following but it errors out (check inline comments). How can I get this working?
protocol Loader {
var contents: String {get set}
init(fromPath: String) // this must be shared
func transform() // each will have its own implementation
}
extension Loader {
init(fromPath: String) {
// error: 'self' used before 'self.init' call or assignment to 'self'
// error: 'self.init' isn't called on all paths before returning from initializer
contents = "read file from fromPath and assign contents here"
}
}
struct DocFileLoader: Loader {
var contents: String
func transform() {}
}
struct CSVFileLoader: Loader {
var contents: String
func transform() {}
}
PS: I checked Init in protocol extension but I could not follow the discussion as I feel (I maybe wrong here) it evolved later into a different problem.
Karl
(👑🦆)
2
Only if the default implementation delegates to another initialiser defined on the protocol or one of its ancestors.
protocol Foo {
init(_: Int)
init(_: Double)
}
extension Foo {
// Works.
init(_ x: Int) {
self.init(Double(x))
}
}
But you can't have a default implementation which provides a memberwise initialiser (one which initialises all the members itself, as in your example), because the object may have more members than the protocol knows about:
protocol Loader {
var contents: String {get set}
init(fromPath: String)
}
struct OhNo: Loader {
var contents: String
var whoInitialisesThis: SomeType
}
3 Likes
crontab
(Hovik Melikyan)
3
Looks like a default constructor is needed here since while parsing the extension the compiler has no chance of knowing what the actual object will look like or for example how contents will be redefined there.
protocol Loader {
var contents: String { get set }
init()
init(fromPath: String) // this must be shared
func transform() // each will have its own implementation
}
extension Loader {
init(fromPath: String) {
self.init()
contents = "read file from fromPath and assign contents here"
}
}
1 Like
vns
4
I'd change the way you structure types to avoid the need to have default init in protocol:
protocol ContentTransformer {
func transform(contents: inout String)
}
struct Loader<Transformer> where Transformer: ContentTransformer {
var contents: String
let transformer: Transformer
init(fromPath path: String, transformer: Transformer) {
self.transformer = transformer
contents = // read from path
}
func transform() {
transformer.transform(contents: &contents)
}
}
2 Likes