Clarifying Swift Access Control (Hint: Swift Isn’t C#)

As it turns out, Swift isn’t C# (or Java or VB.Net or…)! My day job keeps me busy writing C#, so I’ll reference it as my go-to comparison language for this article. The conclusion, however, carries over to other languages that have access control modifiers.

I just spent the greater part of a week experimenting with Swift extensions. I was trying to figure out some seemingly strange behavior that they were exhibiting.

After publishing “3 Nuances of Swift Extensions”, I quickly learned that I had a fundamental misunderstanding of Swift access control, thanks to some observant folks in the Swift community.

What was the hiccup? Read on to find out where I went wrong…

How private is private?

One of the most surprising “nuances” from “3 Nuances of Swift Extensions” that I discovered was that if you define an extension within the same source file as another Type, the extension’s members can see the other Type’s private properties and functions! “Whaaat?? How is this possible?!”, I reacted.

Well… To restate the obvious, Swift isn’t C#… and it isn’t C# in more ways than just syntax.

Ever since access control modifiers were introduced in Xcode 6 Beta 4, I had it in my mind that public, private, and internal worked just like they do in C#. Sure, I read the blog article on access control published by the Swift team, but it was a mere cursory look. I basically saw the three key words and thought, “Ah, I got this… moving on!”

This was a fundamental mistake for me to make, and it goes to show that just because there are similarities between languages, it doesn’t mean the semantics of those similarities carry over.

Semantics of private

Private is the access modifier that got me all confused. The concept of public and internal carry over fairly nicely, but private is the one that’s fundamentally different between C# and Swift, so that’s where I’ll focus.

In addition to this article, recommend giving the Swift team’s original article on access control a very close read, just to make sure all the semantics of public and internal in Swift are clear as well.

Private and C#

In C#, private members of a Type are “truly” private. They are only visible within that Type. The member’s visibility is limited to the curly braces enclosing the Type’s implementation. That’s it. No subclass can see private members. No other Types can see those members, no matter which file those Types are defined in. Private is private.

Private and Swift

And then there’s Swift. Private takes on entirely different semantics in Swift, and herein lay my fundamental misunderstanding. It was obvious that I just didn’t “get it” if you read through the Nuances Article. [sigh]

In Swift, a private Type, or a public/internal Type’s private members are visible to anything else defined within the same file.

This isn’t a characteristic that’s limited to extensions. Anything defined in the same source file as something else can see everything. This is a shocker if you’re coming from C# or a similar language where the semantics of access control are used for encapsulation purposes.

Proof by example

So suppose you have a file named Types.swift, and within you have the following:

1private struct Person {
2    private let name: String
3}
4
5private struct Greeter {
6    private func greet(person: Person) {
7        println("Hi, I'm \(person.name)")
8    }
9}

If you’re a C# developer, you look at that code and immediately go, “Yeah, that’s not gonna work… name is private to Person and can’t be referenced outside that Type”.

But in Swift, this is totally legitimate. Even though Person is private, Greeter can see Person and initialize one, and it can see Person‘s private property, name.

Private in Swift simply limits visibility to Types and members within the same source file. Multiple Types defined in the same source file can see other private Types, as well as other Types’ private properties and functions. In other words, “private isn’t private”, if you’re thinking of private like a C# developer (or a developer familiar with other languages with access control modifiers similar to C#).

Wrapping up

There is a fundamental difference in the semantics of access control between C# and Swift.

In C#, we typically think of access control in terms of inheritance characteristics. The modifiers affect the Type and revolve around the Type and its interaction with other Types.

Swift, controls access to members in terms of source file and module. Types defined within the same source file see everything about each other, including private members. Internal Types and members expand visibility to anywhere within the same module. Finally, public access makes Types and their members visible everywhere, even to Types defined in other modules.

comments powered by Disqus