[swift-evolution] [swift-evolution-announce] [Review] SE-0025 Scoped Access Level

Joe Groff jgroff at apple.com
Sat Feb 27 19:03:57 CST 2016

Drew Crawford via swift-evolution
<swift-evolution at swift.org> wrote:
>> I’m unsure what you are imagining here - compiler protection of class
>> details from within a closure completion handler that is also part of
>> your class definition?
> What i mean here is simply
> class Foo {
> 	///it is undefined behavior to access this variable except from specialQueue
>        private var _specialQueueOnly = 0
> 	public var specialQueueOnly: Int {
> 		var i: I! = nil
> 		dispatch_sync(specialQueue) {
> 			i = _specialQueueOnly
> 		}
> 		return i
> 	}
> }
> The lynchpin of this defensive programming technique is that only these
> 12 lines of code have any risk of a threading bug, and we can trivially
> inspect the 12 lines.  So our safety hangs on two tentpegs:
> 1.  That "private" in "private var _specialQueue" is compiler enforcement
> against other files trying to access this ivar
> 2.  That the file itself is 12 (or other minimal number of) lines and
> trivially inspectable.
> Should we violate any of these constraints, we lose our safety.

Allowing extensions within a module to introduce stored properties might be
another possible way of enabling this, since you could then factor the
private storage and its concurrency-safe accessors into a separate file.
Looking further into the future, our concurrency model will hopefully have
some mechanism for isolating state, by actors or some other means. 


>> It may be that I’m unfamiliar with UITableViewCellContentView (as it is not documented).
> Well, that is kind of the point: Objective-C's access control worked, and
> prevented you from knowing about this class.  
> But to provide a more accessible illustration, consider the case where we
> have some motivation to hide Foo from the rest of our
> framework[/module/target/application/executable/library].  This is more
> likely to happen in a UIKit-sized project, where there are hundreds of
> public classes, and probably thousands of "internal" ones, and a typical
> class has motivation to touch 5 or 6 other classes, of the thousands that may be available.
> In Swift, each internal class is visible to every other class.  But that
> is not especially workable at UIKit scale; if every class can potentially
> reach every other class we are in for an adventure when one of the
> hundred developers on your team decides that some UITableView
> implementation detail you've never heard of should be accessing some
> UILocalNotification detail you've also never heard of.  So we need some
> kind of "fencing" within a large framework to make good neighbors.
> This is solved very easily: we can group several related classes into one
> file, and some of the classes are private.  Many ordinary people today
> group related classes into a file as a fencing mechanism even not at
> UIKit-scale.  So a file can access all of its own classes, but not all
> the classes of other files.  That creates the "fence", and now your
> coworker cannot draw a line between some UITableView secret class and some
> UILocalNotification secret class, and your desk will not be dented from
> the impact of your forehead.
> The problem now is that while fixing this situation we have broken one of
> our safety tentpegs.  We earlier required that Foo.swift be only 12 lines
> for thread safety, but now Foo is contained in a larger file so as to
> create a fence.  So we can solve one of these problems or the other one,
> but never both at the same time.
> "local" effectively resolves this dilemma, because if our
> _specialQueueOnly variable is local, then it is not the /file/ which must
> be kept to 12 lines, but the /scope/.  So we could group an unlimited
> number of classes in Foo.swift, with no loss of confidence for our thread safety.
> A better approach might be to realize that if global scope, target scope,
> and file scope do not solve the visibility problem, perhaps yet another
> scope will not totally solve the problem either.  I fully expect Apple
> will need a "vendor" scope for example (so that UIKit and CoreAnimation,
> two public frameworks, can still have private APIs between them), and I
> bet there are many more kinds of scopes that have not yet occurred to me.
> Behind that realization lies the Rust system, which divorces visibility
> from these arbitrary scopes that we seem to be struggling to fit into. 
> But that proposal isn't before us, and this one is.  I prefer going
> somewhere to staying here.
> Drew
>> On Feb 26, 2016, at 10:34 PM, David Waite
>> <david at alkaline-solutions.com> wrote:
>>> On Feb 26, 2016, at 8:44 PM, Drew Crawford via swift-evolution
>>> <swift-evolution at swift.org
>>> <mailto:swift-evolution at swift.org>> wrote:
>>> Threading is one especially pernicious case.  If I have an ivar that is
>>> only safe for access from one thread, I *need* compiler enforcement.  I
>>> *need* a guarantee that this ivar is only accessed through public
>>> interface methods that can be audited to be threadsafe.  Simply a
>>> doccomment that says "bad programmer, don't do it" is not enough.
>> I’m unsure what you are imagining here - compiler protection of class
>> details from within a closure completion handler that is also part of
>> your class definition? I believe you would only get this with this local
>> scope proposal if you structured your code such that callback blocks
>> were functions outside your type definition.
>> If you are talking about access or modification of the inner state of a
>> class and a manual audit of safety, that audit is of the file and not of
>> the type or extension. I’m unsure if your concern is of having to split
>> code into multiple files for safety, or that there is not a way to split
>> code into multiple files to achieve safety in some particular scenario.
>>> This is not even a matter of "artistic choice" of whether or not I want
>>> to follow "one file per class".  I can achieve thread safety with
>>> "private" ivars and "one file per class", but if my class is
>>> UITableViewCellContentView (which is an implementation detail that
>>> should be hidden even to most of UIKit) I am now forced to expose that
>>> implementation detail to my entire team.
>>> This places me in the unconscionable situation of choosing between
>>> whether I have thread safety or encapsulation, between whether my
>>> coworker will accidentally create a threading bug or accidentally use a
>>> class they ought not to use and I am unable to appropriately hide.
>> I’m not quite sure what you mean here - exposing that your class is a
>> subclass of UITableViewCellContentView? Or that the rest of your team
>> needs to code in different files from your class in order to maintain encapsulation?
>> It may be that I’m unfamiliar with UITableViewCellContentView (as it is not documented).
>> <snip>
>>>> How much effort did you put into your review? A glance, a quick
>>>> reading, or an in-depth study?
>>> I've followed this from the earliest discussions.  I've rethought my
>>> position somewhat in response to the growing uncertainty about dropping
>>> the NS prefix, which I think exposes some very real problems with visibility in Swift.
>>> As that situation has developed, I no longer believe this proposal goes
>>> far enough.  But it does go somewhere, and we should not stay where we are.
>> I don’t understand how an access control proposal pertains to changes in
>> the Foundation public API. What is the ideal end state in your mind, and
>> in what way is this a step toward that?
>> -DW

More information about the swift-evolution mailing list