Private Properties in Protocols

Hey Swift Team!

I want to propose that Protocols can have Private Modifiers to Variables and Functions.

How I implemented my version of Private Properties in Protocols: Used sourcery to copy paste the extensions

The Repository, PDF explanation, and Readme is supplied in this repo

https://github.com/Viranchee/PrivatePropertiesInProtocols

Going through the PDF on the Repository will help explain it as well

Background:

I wanted shared code across multiple ViewControllers.

So I wrote up a protocol & dumped the shared code in the extension

The UI shared code required UI elements to be public (internal) rather than private

This Pull Request got rejected as UI elements went public

So learnt and programmed
Sourcery
to copy the code in Protocol Extension, and paste it below every Class implementing that Protocol

Cheers,

Viranchee Lotia

2 Likes

Protocol methods/properties are supposed to be public/internal/open by their very nature. You can think of a protocol as describing a very specific shape that something should conform to. Having the entirety of the description public is a requirement to having something conform to it.

I looked at your example in the pdf and it looks like your main reasoning is so that you can create a protocol extension to add some default functionality without exposing access to a particular property. I think protocols aren't the right tool for the job here.

Given this statement and your example I feel like inheritance might suit your use case better. Protocols shouldn't be used everywhere for everything you do. In this case I think it's worth looking at all of the tools you have available and picking the right one for the job at hand.

1 Like

I feel like inheritance might suit your use case better.

In this particular use case, yes. If OP is trying to achieve something like mix-ins with internal state, though, then inheritance doesn't easily support that model.

However, I think a protocol-based composition approach would work. Let the VC conform to the protocol, but the methods simply call into another data structure within the VC that actually holds the state and also conforms to the protocol.

Yes this is exactly the use case.

The issue is with private properties inside the Class, they can't be accessed anywhere outside the file, even outside the file extension. This is good feature

A workaround is to have a function accept all the properties which were private inside the Protocol, and have a protocol extension implement the function.

protocol X {
 func doSomething(_ label: UILabel) // the label is private property in a class
}

extension X {
 func doSomething(_ label) { /* implementation */}
}

class ViewController: X {
private var label = UILabel()
func viewDidLoad() {
doSomething(label)
}

/// use this implementation to do the mixin behavior from outside the class
func exposedFunction() {
doSomething(label)
}
}

This way, a superView or another class can trigger private method update by calling the exposedFunction

let vc = ViewController()

vc.doSomething(vc.label) /// ERROR Cannot access private property `Label`
vc.exposedFunction()      /// This Compiles

Your approach should work, but you are exposing the X.doSomething method to the outside world on your VC, and exposedFunction is not codified as the access to X.doSomething. I think the root of your troubles may be that you are trying to hang too much implementation detail on the protocol.

My thought was something more like:

protocol X {
    func doSomething()
}

class Mixin {
    private var state = ...()
    func doSomething(_ label) { /* something with label and state */ }
}

class ViewController : X {
    private var label = UILabel()
    private var mixin = Mixin()        

    func doSomething() { mixin.doSomething(label) }
}

In this approach, the Mixin class can contain all of the mixin-related functionality, rather than trying to hang it off the protocol, and the protocol itself can be better suited to the behavior expected by consumers of the VC.

And, if you need the mixin itself to have some common interface (for example, the actual type of the mixin in the VC might vary depending upon application needs) you can add a mixin protocol as well to better decouple the mixin from the VC.

1 Like

I like the sound of this.

I do feel there are times when using a protocol extension to carry shared functionality (that depends on private properties) rather than a separate data structure would be nice as it avoids us having to inject yet another dependency or creating an object for what may be a very small bit of code.