How to avoid duplicate initializing statement when adopting a protocol?

protocol ManyProperties {
    var a: Int { get }
    var b: Int { get }
    var c: Int { get }
    var d: Int { get }
}

struct S: ManyProperties {
    let a: Int
    let b: Int
    let c: Int
    let d: Int
    
    init(a: Int, b: Int, c: Int, d: Int) {
        self.a = a
        self.b = b
        self.c = c
        self.d = d
    }
}

class C: ManyProperties {
    let a: Int
    let b: Int
    let c: Int
    let d: Int
    
    // duplicate initializing
    init(a: Int, b: Int, c: Int, d: Int) {
        self.a = a
        self.b = b
        self.c = c
        self.d = d
    }
}

I know superclass can solve the problem with super.init(...). But how to solve the problem without a superclass?

If your type remains non-public then you get that behaviour for free on structs, you can simply drop the entire init on S.

I know the default initializer would be provided, but it’s just kind of a trick. What if I’m gonna let every property plus one in init?

I don't understand this question.

I mean if I do this in my initializer:

init(...) {
    self.a = a + 1
    self.b = b + 1
    ...
}

I cannot rely on the default behavior.

Whether it is actually more concise depends on how many properties and types are involved, but the following strategy can be useful sometimes:

// The real public interface.
public protocol ManyProperties {
    var a: Int { get }
    var b: Int { get }
    var c: Int { get }
    var d: Int { get }
    init(a: Int, b: Int, c: Int, d: Int)
}

// The internal shared implementation.
internal struct ManyPropertiesStorage {
    let a: Int
    let b: Int
    let c: Int
    let d: Int
}
internal protocol InternalManyProperties : ManyProperties {
    init(storage: ManyPropertiesStorage)
    var storage: ManyPropertiesStorage { get }
}
extension InternalManyProperties {
    public var a: Int { return storage.a }
    public var b: Int { return storage.b }
    public var c: Int { return storage.c }
    public var d: Int { return storage.d }
    public init(a: Int, b: Int, c: Int, d: Int) {
        self.init(storage: ManyPropertiesStorage(a: a + 1, b: b + 1, c: c + 1, d: d + 1))
    }
}

// Short and sweet conformances.
public struct A: ManyProperties, InternalManyProperties {
    internal let storage: ManyPropertiesStorage
}
public struct B: ManyProperties, InternalManyProperties {
    internal let storage: ManyPropertiesStorage
}
public struct C: ManyProperties, InternalManyProperties {
    internal let storage: ManyPropertiesStorage
}
public struct D: ManyProperties, InternalManyProperties {
    internal let storage: ManyPropertiesStorage
}

I don’t know what the “problem” actually is?

A property requirement can be satisfied with stored properties or computed ones. And your protocol doesn’t have an initializer requirement, and so doesn’t impose how you get the values in there to begin with.

This would be legal:

struct MyType: ManyProperties {
    var a: Int { return Int.random(0..<10) }
    var b: Int { return Int.random(0..<100) }
    var c: Int { return Int.random(-10..<10) }
    var d: Int { return Int.random(0..<1) }
}

So, can you explain more what the problem is?

Terms of Service

Privacy Policy

Cookie Policy