C# and Java programmers are used to working with class member access level modifiers like public
, private
, and protected
. With the latest version of Swift (which came with the latest version of Xcode), we got access level modifiers too. They’re just a little bit different.
Prior to Xcode beta 4, there was one and only one level of access in Swift. Now there are three:
private
– accessible only from within the source file where it’s defined,internal
– accessible only from any file within the target where it’s defined, andpublic
– accessible from any file within the target where’s it’s defined, and from within any other context that imports the current target’s module.
In case you’re not clear on what’s meant by a target: it’s the end result of doing a build in Xcode. For most of us, this is likely an app, but it could also be a library, framework or unit test bundle.
These levels of access are file-based rather than class-based. To help make things clear, I’ve put together some illustrations.
The default access level: internal
The first level of access I’ll cover is internal
…
An internal
entity can be “seen” within the file where it’s defined, as well as from any other file in the same application or framework.
internal
is the default level of access, and the only access level in versions of Swift prior to beta 4. If an entity — that is, a variable, constant, enum, struct, or class — doesn’t have a specified access level, its access level is internal
.
The locked-down access level: private
The next level of access is private
…
A private
entity can be “seen” within the file where it’s defined, and only within that file. It’s invisible from outside that file.
If you’re used to the sort of access C# or Java programmer, you’re used to the idea of a private
entity being one that can’t be “seen” outside the class. In Swift, access level is about files, not classes, meaning that a Swift private
entity is one that can’t be seen outside its own file. Two Swift classes in the same file would be able to access each other’s private
variables, methods, and so on. This approach will make it possible to encapsulate related classes in a single file, with “internal use only” classes marked as private
. It also gets around having to use access kludges like C++’s friend
functions and classes.
The “putting myself out there” access level: public
Just as private
is a little bit different from what you might expect, so is public
…
A public
entity can be “seen” within the file where it’s defined, from any other file in the same application or framework, and by another file any other application or framework that imports the application or framework where the public
entity was defined.
Once again, if you’re a C# or Java programmer, this may seem weird. Swift’s internal
is closest in spirit to C#’s and Java’s public
; Swift’s public
exposes entities to outside code that imports our application or framework. This should come in particularly handy for those of you who are writing libraries: you can choose which classes and methods to expose to clients by marking them as public
.
Trying out the new access levels
The following is a copy-and-paste from some code I wrote while taking these new access levels for a spin. I created a file called RelatedClasses.swift that contain classes named SomeClass
, SomeOtherClass
, and HiddenClass
:
// RelatedClasses.swift class SomeClass { internal func doSomethingInternal() -> () { println("SomeClass::doSomethingInternal() called.") } func doSomethingDefault() -> () { println("SomeClass::doSomethingDefault() called.") } private func doSomethingPrivate() -> () { println("SomeClass::doSomethingPrivate() called.") } } class SomeOtherClass { let someClassInstance = SomeClass() private let hiddenClassInstance = HiddenClass() func usePrivateMethodInSameFileDifferentClass() -> () { someClassInstance.doSomethingPrivate() } } private class HiddenClass { }
Note that:
SomeClass
has two internal methods:doSomethingInternal()
anddoSomethingDefault()
.doSomethingInternal()
‘sinternal
access level is explicit, anddoSomethingDefault()
‘sinternal
access level is explicit. Both these methods are callable from inside RelatedClasses.swift, or from any file inside the application or framework containing RelatedClasses.swift.SomeClass
also has aprivate
method:doSomethingPrivate()
. It’s accessible from withinSomeClass
, but also from anywhere else inside RelatedClasses.swift, including from within the other two classes. You can’t call this method from outside RelatedClasses.swiftSomeOtherClass
contains an instance ofSomeClass
andHiddenClass
. Note that becauseHiddenClass
isprivate
, any instance ofHiddenClass
must also be declaredprivate
.SomeOtherClass
has a method with the rather long nameusePrivateMethodInSameFileDifferentClass()
, and it lives up to its name. It can accessSomeClass'
doSomethingPrivate()
method even though it’sprivate
because it’s in the same file, and Swift’s access control is more file-based than class hierarchy-based.HiddenClass
is aprivate
class. SinceSomeClass
andSomeOtherClass
are in the same file, they can “see” it and create instances of it. Its definition is “invisible” outside the file, and thus you can’t create aHiddenClass
instance outside of RelatedClasses.swift.
As you can see, Swift’s access control is different from C#’s and Java’s, which will lead to different coding patterns. We typically see the one-class-per-file approach in C# and Java, but Swift’s different kind of private
access will likely give rise to larger-scale type of encapsulation, with related classes in the same file. public
may change the way people write libraries and frameworks — I’m more of a library/framework user than a writer, so I’ll leave it to others to deliver more informed comment on that. It’ll be interesting to see the approaches that programmers come up with as they use Swift.
Recommended Reading
The online Swift documentation has been updated to cover the addition of access control in beta 4. There’s also some interesting discussion about Swift’s access levels in the Human Friendly’s blog, in an article titled Swift Access Controls are like C’s (and that isn’t necessarily a bad thing).
2 replies on “A first look at Swift’s new access levels”
[…] A first look at Swift’s new access levels […]
[…] this link for a more in-depth […]