<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Now that the scoped access discussion is close(r) to being settled, let's tackle the next controversial topic: protected.<div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">Expose<br class=""></b><div class=""><br class=""></div><div class="">Objective-C allows multiple “APIs” to be exposed for a given class by virtue of writing additional header files. There are two common uses of that:</div><div class=""><br class=""></div><div class="">Use case 1: API for private clients</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">Foo.h</div><div class="">Foo-Private.h</div><div class="">Foo.m</div></blockquote><div class=""><br class=""></div><div class=""><div class="">Use case 2: API for subclasses, intended to be overridden</div><div class=""><br class=""></div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class="">Foo.h</div><div class="">Foo-Subclasses.h // defines a method to override, e.g. layoutSubviews</div><div class="">Foo.m</div><div class=""><br class=""></div></blockquote>Use case 3: API for subclasses, intended to be called<br class=""><br class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class="">Foo.h<br class="">Foo-Subclasses.h // defines a dangerous helper method<br class="">Foo.m<br class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><br class=""></div></blockquote></blockquote></div><div class="">Swift covers use case #1 with the internal (or perhaps soon-to-be moduleprivate) access modifier.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">The problem</b></div><div class=""><br class=""></div><div class="">Swift core teams has prompted us to explore using internal and file-private access levels to cover use cases #2 and #3, and I've faithfully tried to do just that. It works for <i class="">many</i> cases inside the code of <i class="">apps</i>, but it doesn't work if you're writing a library package and want to expose the “special extenders club” API to the clients of the library.</div><div class=""><br class=""></div><div class="">Here's the use case in more detail:</div><div class=""><br class=""></div><div class="">1. You have a library that exposes a class called Foo.</div><div class="">2. There are two different ways to use that library: you can just use Foo, or you can extend the library, <i class="">perhaps</i> subclassing Foo.</div><div class="">3. Those who opt for the second way to use the library (i.e. extending it) need access to a broader set of APIs.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">Why do extenders need access to a broader set of APIs?</b></div><div class=""><br class=""></div><div class="">Basically, for safety and documentation purposes.</div><div class=""><br class=""></div><div class="">Considering use case #2:</div><div class=""><br class=""></div><div class="">The library often exposes very similar APIs, some of which are intended to be called (layoutIfNeeded), others intended to be extended (layoutSubviews). These typically sound very similar, and are easy to mix up, so you definitely want to document this difference, and ideally you also want to statically prevent the first (non-extending) type of clients from calling them.</div><div class=""><br class=""></div><div class="">Note that accidentally calling layoutSubviews instead of layoutIfNeeded is one of the worst kinds of mistakes; it might seem to work, and it might not be found until production, and the bug it causes may be weird and difficult to reproduce.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><div class="">Considering use case #3:</div></div><div class=""><br class=""></div><div class="">A library may expose methods that should not be called by normal clients, but are useful when extending it:</div><div class=""><br class=""></div><div class="">3.1) They may carry substantially different guarantees from normal methods (e.g. require to be called only on a certain dispatch queue),</div><div class=""><br class=""></div><div class="">3.2) or may only be callable while another overridable method is executing,</div><div class=""><br class=""></div><div class="">3.3) or may simply allow mutating the internal state of the class (e.g. the state of UIGestureRecognizer) that is not supposed to be mutated from outside.</div><div class=""><div class=""><br class=""></div><div class=""><br class=""></div></div><div class=""><div class="">Swift currently requires making all of this public. :-(</div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">The problem has tons of prior art.</b></div><div class=""><br class=""></div><div class="">C family of languages use multiple header files.</div><div class=""><br class=""></div><div class="">Ada has special access rules for subpackages (nicely explained in <a href="http://blog.spacesocket.com/2012/07/31/ada-child-packages/" class="">http://blog.spacesocket.com/2012/07/31/ada-child-packages/</a>).</div><div class=""><br class=""></div><div class="">OOP languages have protected access levels.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">What does extending mean in Swift?</b></div><div class=""><br class=""></div><div class="">I'm not sure about this. It certainly needs to include subclassing a class, but we may find other useful meanings.</div><div class=""><br class=""></div><div class="">In particular, writing an extension for a struct/class/protocol may raise similar concerns and may need similar treatment.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">What do I propose?</b></div><div class=""><br class=""></div><div class="">I'm mainly looking for ideas and discussion, but as a strawman, let me put this out:</div><div class=""><br class=""></div><div class="">Introduce <b class="">protected</b> access modifier that allows the member to be accessed by:</div><div class=""><br class=""></div><div class="">1. Subclasses of a class.</div><div class="">2. Extenders of a struct or protocol.</div><div class="">3. Implementors of a protocol. </div><div class=""><br class=""></div><div class="">package FooKit:</div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><br class=""></div><div class="">public class Foo {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>public func amSafe() { ... }</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>protected func amDangerous() { ... }</div><div class="">}</div></blockquote><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><br class=""></div><div class="">public struct Boo {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public func amSafe() { ... }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>protected func amDangerous() { ... }</div><div class="">}</div><div class=""><br class=""></div><div class=""><div class="">public protocol Moo {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>func amSafe()</div><div class="">}</div></div><div class=""><br class=""></div><div class="">public extension Moo {</div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>protected func amDangerous() { ... }</div></div><div class="">}</div><div class=""><br class=""></div></blockquote></div>App:<div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>public class Bar: Foo {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>public func bar() {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>amDangerous()</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}<br class=""><div class=""><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public extension Foo {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>public func boz() {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>amDangerous()</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}<br class=""></div></div><div class=""><br class=""></div><div class=""><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public extension Boo {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>public func boz() {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>amDangerous()</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}<br class=""></div></div></div><div class=""><br class=""></div><div class=""><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public class Boz: Moo {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>public func fubar() {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>amDangerous()</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}<br class=""></div></div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">So what do you think?</b></div><div class=""><br class=""></div><div class="">A.</div></div><div class=""><br class=""></div></div></body></html>