[swift-evolution] Simplifying Access Using 'Hidden'
Joanna Carter
joanna at carterconsulting.org.uk
Wed Feb 15 05:29:49 CST 2017
> The beauty of Swift 2's access modifiers was that they were based around files and modules, explicitly rejecting types and scopes as units for determining visibility. It seems at base there's a group of people who reject that decision altogether. Hence, new `private`, proposals around `protected`, `friend`, `hidden`, `extensible`, etc.
I suppose, for those coming from an Objective-C only background, any extra visibilities are seen as a bonus.
For those coming from a Pascal background, file-based visibility seems more natural.
But for those of us who have used languages like C++ and C#, losing the visibilities that we have been used to can seriously affect how we think and design stuff.
FMPOV, it would seem that one of the "features" of Swift is a much more protocol and struct approach to design. Instead of using class inheritance to add functionality to an entity, we are encouraged to use extensions.
But, in so doing, those of us who are used to inheritance find that we can no longer limit visibility to a "hierarchy" but, instead, when we want to extend a type whilst accessing "privileged" members, we either have to put all our extensions in the same file as the base type, or raise the visibility of those privileged members to internal scope, thus allowing code anywhere in the same module to access and/or mutate it.
I have read https://developer.apple.com/swift/blog/?id=11 and I can see the reasoning against protected explained there but…
Once again, I see the "it was good enough for Objective-C" reasoning being a strong driver here but, this is Swift, where things can be done differently/better.
Allowing internal scope visibility is less of a problem when you are the only one writing the module and know intimately the intent and purpose of everything but when working in a team environment, it is all too easy for another developer to start "interfering" with your carefully designed logic by using it in ways that you had not anticipated.
I can understand the reasoning behind not using the concept of protected visibility but still feel that there are times when restricting visibility only to extending entities, whether that be subclasses of a class or extensions of any type, including structs and enums.
I would also like to argue that the use of open vs public for classes is quite confusing when we already have the option of marking a class or its members as final ; which seems to do much the same as leaving a class as public.
Except open is not truly a restriction of visibility, it is more a restriction on inheritance.
To quote the above blog, "In contrast, protected conflates access with inheritance". Surely "open" also conflates access with inheritance? It affects, not what external code can see but how the inheritance chain is controlled, as does final. In fact, I would dare to say that the difference between open/public and final is possibly too fine to be of sufficient importance to justify the existence of both ; or, at least, it is sufficiently confusing to encourage newer developers to throw their hands up in despair and simply leave everything as internal or public until they stumble across a compilation error.
The only real difference I can make out between open/public and final is that, once again, open/public is more module-based, whereas final is class based.
Why, when we are allowed final as a class only modifier, can't we have protected as a class only visibility?
Or, as I have mentioned previously, should we have a much more "Swifty" version of protected that allows more concisely defined visibility, not only within class hierarchies, but also within the full range of Swift "hierarchies", otherwise known as extensions?
My suggestion of "extensible" is intended to replace the perceived need for "protected" for classes, whilst unifying that concept of privileged access within a class hierarchy, with a similar, and increasingly demanded, privileged access for extensions of all types.
To elucidate further :
Before Swift, if we wanted a hierarchy of types, all with common base behaviour, without having to write the same code in every type, we were limited to using classes with their visibilities of private, protected and public.
Now Swift encourages us to declare protocols, which can have extensions that can define base behaviour, as long as that behaviour doesn't include stored data. We can then "inherit" that behaviour either in classes, structs or enums that implement the "base" protocol.
So, an interesting question is : should we look at getting rid of class inheritance altogether in favour of "protocol-based inheritance"?
Oh, and finally for this post, can anyone please tell me exactly what fileprivate brings to the table?
To my mind, although it allows access to private members of another type, it also requires that any type, wishing to take advantage of that privilege, has to be declared in the same file ; so, sort of like protected visibility but on a file basis.
But what if I have a relatively small abstract type (protocol or class) that is the basis of a larger "hierarchy"? Using fileprivate in the base type would mean that I would have to declare my whole hierarchy within that one file instead of placing each "subtype" or "implementing type" in their own files.
What happened to the "types should only be one screenful" school of thinking? :-)
--
Joanna Carter
Carter Consulting
More information about the swift-evolution
mailing list