[swift-evolution] protocol based invocation forwarding

David Owens II david at owensd.io
Mon Dec 7 15:33:52 CST 2015


Often it is the case where one might want to implement a type that provides an interface but has inner components that actually handle the implementation. In those cases, we end up with a lot of boiler-plate code that simply turns around and invokes the on the instance.

Let’s take the example of class clusters:

private protocol _Cluster {
    func description() -> String
}

class Cluster: _Cluster {
    
    private var _instance: _Cluster
    
    init(name: String) {
        _instance = _ClusterString(name: name)
    }
    
    init(value: Int) {
        _instance = _ClusterValue(value: value)
    }
    
    // this is pure boiler-plate
    func description() -> String {
        return _instance.description()
    }
}

private class _ClusterString: _Cluster {
    private var name: String
    init(name: String) { self.name = name }
    func description() -> String {
        return "_ClusterString: \(name)"
    }
}

private class _ClusterValue: _Cluster {
    private var value: Int
    init(value: Int) { self.value = value }
    func description() -> String {
        return "_ClusterValue: \(value)"
    }
}

let s = Cluster(name: "a string")
s.description()

let v = Cluster(value: 12)
v.description()


Now, it would be nice to not have to have to implement the boiler-plate (this example only has a single method, so the savings seem minimal).

class Cluster: _Cluster {
    @forward(_Cluster, _instance)

    private var _instance: _Cluster
    
    init(name: String) {
        _instance = _ClusterString(name: name)
    }
    
    init(value: Int) {
        _instance = _ClusterValue(value: value)
    }
}

The @forward(protocol, instance) attribute lets the compiler know that the _Cluster protocol should be forwarded to the _instance value. The compiler would then generate all of the implementation stubs. Refactoring is also made simple as API changes to _Cluster do not need to be manually reflected on the type.

Another way to solve this problem is with a sufficiently advanced macro system. But that is out-of-scope for v3. However, this seems like it could be a straight-forward enough implementation to support in the mean-time, with an easy path for removal/update if it were to be replaced by a macro system.

-David

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151207/a3ee1114/attachment.html>


More information about the swift-evolution mailing list