Swift Protocol Oriented Mixed Scope

315 Views Asked by At

I have a Protocol Oriented Programming conceptual question. Let's say I am creating a protocol Foo, and I want to extend Foo with a function action() in a protocol extension. action() will always be mostly the same, no matter who is implementing, so I don't want to have to repeat this code. The only part of action() that changes is prop, and prop needs to be an instance property. So my conforming struct should simply need to have prop defined, and then action will work correctly. This code is fine and looks like this:

protocol Foo {
    var prop : String {get set}
}
extension Foo {
    func action() -> String {
        return prop + ": Applied Action."
    }
}

But now here is the catch. Let's say prop is information that I don't want other classes to have access to. I want them to only access it through action(). In current swift, prop must be at least internal, because the protocol is internal, but I need it to be private so that consuming classes can't accidentally modify the property or read information that I only want them to have access through action(). I could add action() to the protocol, but then I need to rewrite action() every time a struct conforms.

This same example could be extended to a function as well:

protocol Foo {
     //customization point by conforming class
    func customAction(str: String) -> String
}
extension Foo {
    func action() -> String {
        //Do some default work
        let str = "some string created from previous default work"
        return customAction(str: str)
    }
}

action() will always be the same implementation, except for cusotmAction(). So, I need conforming classes to implement customAction(), but I don't want any outside classes to call customAction() since it only provides some specific behavior that should only be used inside of action(). Therefore I need customAction() to be private, but again, this is not possible.

So here is my question, is this just a breakdown in Protocol Oriented Programming? How can I use protocols to write this type of code without giving prop/customAction() too much scope or without having to rewrite the same code inside of action() over and over again? This example is fairly simple, but I am facing more complex versions of the same problem. Is there a different way to look at this problem in terms of POP, or should I be looking at a more object oriented approach?

1

There are 1 best solutions below

3
On

I don't believe this is necessarily a fallback of Protocol-Oriented Programming as a concept but merely of the language in which you are using it. Perhaps Swift was not designed with cases like these in mind. However, I think one approach to solving this problem would be to use composition in which you create an object that you want functions such as action to be defined in which make use of state that is not accessible from outside. Take a look at this example:

struct Foo {
    init(prop: String) {
        self.prop = prop
    }

    func action() -> String {
        return prop + ": Applied Action."
    }

    private let prop: String
}


class Test {
    let foo = Foo(prop: "TEST")
}

In this case, Test can define its own prop much in the same way (but not exactly like) it would if it used a protocol. That being said, you could now call all the functions on foo inside of an instance of Test without having any access to the underlying variables. Doing it this way (with composition) also keeps you clear of the inheritance problems which lead people to use POP in the first place. I hope this helps!