I am the author of iOS 17 Fundamentals, Building iOS User Interfaces with SwiftUI, and eight other courses on Pluralsight.
Deepen your understanding by watching!
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.