[swift-evolution] private(call) and internal(call)

Félix Cloutier felixcca at yahoo.ca
Mon Jan 11 22:33:40 CST 2016


This is the reply that I wrote to someone else who wanted a private(extension) <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005450.html> modifier. Swift's access modifiers align with linker access modifiers and visibility styles: `private` is not exported beyond the translation unit (and can be very aggressively optimized), `internal` is hidden (not exported to the dynamic symbol table) and `public` is exported to the symbol table of the resulting executable. `Private(set)` just means that the setter method is not exported but the getter is. 

So as I said in the other thread, I wouldn't consider that these new modifiers follow the example that private(set) set.

The great thing about using the linker to implement access control is that it can be enforced. The reason internal or private can't be called from outside an executable is that no data about it exists in the final executable As a matter of fact, the symbol itself might not even exist in the fully optimized executable.

I also think that it's fundamentally the same as protected, because nothing prevents you from sharing the logic outside. You can forward the protected call to a public call, which is exactly the same as a public call forwarding to a protected call in terms of encapsulation.

If I can toot my horn, you should consider as an alternative better cooperation between the language and the autocomplete/linters <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005807.html>. I haven't got around to a new proposal with documentation comments yet but the idea's there.

Félix

> Le 11 janv. 2016 à 19:53:57, Charles Srstka via swift-evolution <swift-evolution at swift.org> a écrit :
> 
> Motivation:
> 
> The Cocoa frameworks have a long-standing issue regarding methods that are intended as primitives for subclasses to override or for protocol implementers to provide, but which aren’t meant for client code to call directly. Often, the only way to determine that a method shouldn’t be called is to look at the documentation, but that isn’t much of a help when auto-complete suggests such methods, which sometimes look perfectly usable, even tempting, to the naked eye. NSView has a number of them that have come up many a time on mailing lists and support forums in the past, to the extent that Apple has actually created a chart intended to indicate which should be called directly and which shouldn’t:
> 
> https://developer.apple.com/library/mac/releasenotes/UserExperience/RNAutomaticLayout/#//apple_ref/doc/uid/TP40010631-CH1-SW14 <https://developer.apple.com/library/mac/releasenotes/UserExperience/RNAutomaticLayout/#//apple_ref/doc/uid/TP40010631-CH1-SW14>
> 
> Clearly advertising things that are not supposed to be actually called is non-ideal in terms of interface.
> 
> Proposed Solution:
> 
> Following the example of private(set), I propose a new access modifier for methods and properties called private(call). A method declared private(call) would behave exactly the same as a private method in almost all circumstances, the one exception being when a subclass attempts to override it (for a class) or a class, struct, or enum implements it (for a protocol). These methods would not be callable by any code outside of the source file that declared the property, and would not show up in code completion.
> 
> A similar access modifier, internal(call), would allow the method to be called only by code in the same module, but publicly would be override/implement only.
> 
> Wait, isn’t this the same as protected?
> 
> No. The difference between this and protected is that while protected allows subclasses to access the method and/or property as if it were public, private(call) does *not*. Subclass code is forbidden from accessing the member, exactly as any code from any other class would be. This makes implementation simpler than it would be for protected; private(call) can be treated exactly the same as private for all use cases other than:
> 
> 1. Displaying the generated “headers” to show the class or protocol’s interface.
> 
> 2. A method or property declaration in a source code file that either begins with “override” or implements a required member of a protocol.
> 
> In all other cases, the compiler can treat private(call) and internal(call) exactly as it would private and internal respectively. It is also more secure than protected, since it cannot be worked around simply by making a subclass of the class in question, and since it reduces the ways a subclass can do something unexpected with the property or method.
> 
> Alternatives Considered:
> 
> In some cases, an exception could be made for Objective-C methods marked OBJC_REQUIRES_SUPER; in such cases, the subclass could be allowed to call super’s implementation, but only from within the override. This could be extended to pure-Swift classes once Swift acquires an equivalent to OBJC_REQUIRES_SUPER. Other than this one exception, even subclasses would not be able to call a method marked private(call). This would, however, complicate the implementation somewhat, and may not be necessary, since any work that the superclass needs to do could be done in a separate method, before calling the private(call) method. There may be some cases where the subclass wants to begin with the return value from the superclass method and modify it slightly, however, in which case this variant may be helpful. It could also possibly be useful in cases where there is a chain of subclasses going several layers down, where each subclass wants to do the work of its own superclass’s implementation before continuing.
> 
> Summary:
> 
> All in all, I think this would be a positive contribution to the language. What do you think?
> 
> Charles
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160111/7c1393eb/attachment.html>


More information about the swift-evolution mailing list