Modifier for classes to make their fields and methods private by default

There has been debate about whether the default access control should be private or internal. It seems like having a class-level modifier would solve many of the complaints voiced in that thread.

Here are, I would imagine, the pros and cons of a class-level modifier to make things private:
Pros

  • All the pros of private visibility by default (promotes good OOP encapsulation and leads to better build times)
  • Allows people not to worry about private visibility if they don't want to
  • Allows people not to worry about private visibility if they're still learning the basics

Cons

  • Require each class to be changed for it to have private visibility

It might look like @privateMembers class MyClass

It could also be generic for any visibility level, like @memberVisibility(private) MyClass. I don't care either way, my main goal is to make private visibility easy. Or, maybe there's something better than a class-level modifier that still easily adds private visibility across many fields. Similar alternatives are welcome.

Perhaps mirror the existing way we change the visibility of the setter for properties:

public private(set) property: Type { … }

Thus:

public private(members) class Foo { … }

Though it is not quite the same in effect, since a public class does not by default have public members, unlike properties where a public property has both a public getter and setter.

Any changes or additions to such a fundamental part of the language is going to require all Swift users to understand and learn those changes. And while I won't say that the access control model should be marked as completely finalized, I really don't see additions that are more about programmer convenience reaching the bar for changes to the model. I think any changes to the model should either be adding something that allows new functionality or API design (like private protocol methods or private enum cases.)

2 Likes

The proposed changes are purely additive. Code that doesn't use them is not changed at all. Is there something about these additions in particular that you see as more harmful than all the other proposed additions the language?

The biggest issue for me is the internal by default visibility that forces you to have subproject to define separate modules or split code in cocoapods for example. Java and Kotlin's approach of folder based packages and the package visibility allows good flexibility and better access control.

Right now, it all is public by default unless you put in the work and put up with splitting your code in modules (not as simple as it would be splitting into Java packages).

This already exists in the form of the shorthand access modifier for extensions, which deliberately works differently from access modifiers for types for this very use case. During the many debates on access control this feature has been explicitly maintained.

An analogous shorthand for types would have to be lexically scoped (it could not reasonably work otherwise), and thus it would be analogous to the existing feature for extensions but for the limitation around stored properties that can be lifted (at least for same-file extensions) as already has been discussed previously.

I see nothing new here to warrant retreading the same topic. (And as to the default access level for Swift, that topic is conclusively closed I think.)

3 Likes

To be fair, this is a tooling limitation. I have been making multi-module projects for years and recommend it. With Xcode 11 it is breezy to split out modules provided you use a Package.swift for projects.

1 Like

This already exists in the form of the shorthand access modifier for extensions, which deliberately works differently from access modifiers for types for this very use case . During the many debates on access control this feature has been explicitly maintained.

Private extensions simply don't solve this use case, because they don't allow stored properties. Also, using extensions as a replacement means you have to organize your methods in terms of their visibility, which some developers do not want.

it would be analogous to the existing feature for extensions but for the limitation around stored properties that can be lifted

It would not be analogous, because of that issue with method ordering. And anyways, stored properties in extensions would be nice in the context of this issue, but I'm not going to try to open that can of worms. This is an alternative with the benefits of that without getting into any extension debates.

This is a significantly different thing from extensions, and just because we want to keep extensions a certain way doesn't mean we can't add a modifier for classes.

Currently, you can intermix methods with different visibility by specifying the access modifier explicitly, or you can group them together using extensions. Swift is explicitly an opinionated language; it is a non-goal (and, in the context of access modifiers, I would argue an anti-goal) to enable arbitrary variations in preferences as to code organization.

2 Likes

This would not add a new method of code organization, it would merely augment the first of the two methods you mentioned.

Any other thoughts?

I don't really like the idea of an annotation. But I do find the possibility to avoid repeated "private"s interesting, maybe something like this could work?:

class Foo {
    private {
        var so: Int
        var much: String?
        var hidden: Bool
        var state: Something

        func someHelper() -> Bool { ... }
    }

    var thisIsStillInteral: Double

    internal {
        var butSoIsThis: Int
    }

    public {
        func myOnlyPublicMethod() -> Void { ... }
    }
}

I haven't really thought this through tho, just throwing ideas out there.

I always thought this approach was reasonable to consider. However, this has been put out there (more than once) during the previous discussions I alluded to above, and it has not been adopted. I’ll leave it as an exercise to the reader to find the arguments for and against the idea laid out during those debates.

1 Like

What about allowing stored properties to be declared in extensions in the same file as the primary type declaration? I believe there is already something in the language that works like that.

Every time we add another annotation to the language, we're effectively adding a new keyword. So while I think the overall idea is good, yet another annotation isn't the way to go, IMHO.

Just need to have one module per class and thus internal becomes the new private.

But that might not be practical.

This would be great, then you could just have a private extension using things that already exist in the language.

Terms of Service

Privacy Policy

Cookie Policy