Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
Swift allows developers to control the context their types, methods, and
other names can be used from. Swift access control, as noted in Apple’s developer docs:
restricts access to parts of your code from code in other source files and modules. This feature enables you to hide the implementation details of your code, and to specify a preferred interface through which that code can be accessed and used.
Swift provides three levels of access:
Internal is Swift’s “do what I mean” default access level for all types.
There is one guiding principle: You can’t build a more public entity out of a more private entity.
On its face, this seems a natural rule. If I need to pass an object of a private type to a function,
there’d be no way for anyone to create that object unless they could
also call a private function. So the private wins out, and the function must be annotated private as well.
But working out the details of this principle across the many mechanisms for assembling instances of new types out of other types that Swift offers becomes quite complex.
This leaves room for surprising interactions. Take this seemingly innocuous UIViewController
subclass as public
, for example:
class ViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
What happens if you open the view controller up to public access?
-class ViewController : UIViewController {
+public class ViewController : UIViewController {
Well, surprise!
ViewController.swift:4:19: Overriding instance method must be as accessible
as the declaration it overrides
Since the boilerplate for a new UIViewController
includes quite a few
more overridden methods than that, that single word change in fact triggers
a wave of red compiler errors.
Oops.
What happened here was an unpleasant interaction
between the default access level for a method
and how inheritance handles access levels.
A subclass must preserve the accessibility of its superclass’s methods
wherever the subclass might be used directly.
Otherwise, we would violate the substitution principle
that allows us to treat all kinds of UIViewController
as just another UIViewController
.
Recall that the default access level is internal.
An internal type can’t have public methods,
so we couldn’t make the override public, anyway.
Anyone that could work with an instance of our internal type,
could also call our internal methods.
So the superclass’ public methods are still as accessible as they can be, and no harm is done.
As soon as we upgraded the class to public accessibility,
anyone could use our class. But not anyone could call an internal method,
and the default access level in a public class remains internal, so the compiler compels us to make the override public as well.
We started with a seemingly simple guideline:
You can’t build a more public entity out of a more private entity.
But now we’ve wandered into the thick of it.
Inheritance and protocol conformance
lead to the most subtle interpretation of the guideline.
Most other forms of building new entities from others
yield to straightforward application of the guideline:
But classes and structs themselves have a lot going on.
Default initializers, superclasses, protocol conformance
and overrides all come together in these entities. You might be able to derive the resulting rules from the guideline,
but for these common cases, it’s likely faster to just learn the rules by rote:
Swift brings us access control driven by a guideline
we can colorfully paraphrase as “privacy spreads like the plague.”
This has some straightforward implications,
and some surprising ones.
If you want the word from the source, see The Swift Book. We’re also hard at work of a Swift programming guide of our own, and plan to publish it next year. Otherwise, you’ll internalize these fastest the classic way:
Head down, write code!
Our introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
The Combine framework in Swift is a powerful declarative API for the asynchronous processing of values over time. It takes full advantage of Swift...
SwiftUI has changed a great many things about how developers create applications for iOS, and not just in the way we lay out our...