A first look at Swift’s new access levels

by Joey deVilla on July 23, 2014

privacy

swift kickC# 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, and
  • public – 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

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

private

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

public

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:

Note that:

  • SomeClass has two internal methods: doSomethingInternal() and doSomethingDefault(). doSomethingInternal()‘s internal access level is explicit, and doSomethingDefault()‘s internal 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 a private method: doSomethingPrivate(). It’s accessible from within SomeClass, but also from anywhere else inside RelatedClasses.swift, including from within the other two classes. You can’t call this method from outside RelatedClasses.swift
  • SomeOtherClass contains an instance of SomeClass and HiddenClass. Note that because HiddenClass is private, any instance of HiddenClass must also be declared private.
  • SomeOtherClass has a method with the rather long name usePrivateMethodInSameFileDifferentClass(), and it lives up to its name. It can access SomeClass' doSomethingPrivate() method even though it’s private because it’s in the same file, and Swift’s access control is more file-based than class hierarchy-based.
  • HiddenClass is a private class. Since SomeClass and SomeOtherClass 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 a HiddenClass 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).

Leave a Comment

{ 1 trackback }

Previous post:

Next post: