Sent from my iPad

> On Feb 25, 2017, at 12:12 AM, David Waite via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>>> On Feb 23, 2017, at 2:56 PM, Nevin Brackett-Rozinsky via swift-evolution 
>>> <swift-evolution@swift.org> wrote:
>> 
> 
>> 
>> The prevailing view from recent discussions is that there should be just one 
>> access level more fine-grained than ‘internal’, and it should be spelled 
>> ‘private’. Let us leave aside for the moment what its exact meaning should 
>> be, and consider the other end of the scale.
> 
> I think the submodule discussion now goes against this being a prevailing 
> view - submodules are directly tied to be an access control level *above* 
> private/fileprivate.
> 
> My expectation is that with submodules, “fileprivate” would go away.
> 
>> Moreover, object-oriented programming is just as much a first-class citizen 
>> in Swift as protocol-oriented programming is, so we should treat it as such. 
>> Classes are inherently inheritable: when one writes “class Foo {}”, then Foo 
>> has a default visibility of ‘internal’, and by default it can have 
>> subclasses. That is a straightforward model, and it is easy to work with.
> 
> There is nothing about OOP which requires subclass-based polymorphism. Rust 
> and Go are two examples of modern languages that do not support subclassing 
> at all.
> 
> In reality, there is less agreement on what “Object Oriented Programming” 
> means to technologists than there is about the real meaning of “Moore’s Law"
> 
>> One of the reasons ‘public’ was previously chosen for closed classes is to 
>> provide a “soft default” for library authors, so they can prevent 
>> subclassing until they decide later whether to allow it in a future release. 
>> This is a misguided decision, as it prioritizes the convenience of library 
>> authors over the productivity of application developers. Library authors 
>> have a responsibility to decide what interfaces they present, and we should 
>> not encourage them to release libraries without making those decisions.
> 
> I think SE-0117 and the discussion behind it is pretty clear about why this 
> is the default. It is not about convenience, but safety.
>> 
>> Moreover, we need to trust client programmers to make reasonable choices. If 
>> a library mistakenly allows subclassing when it shouldn’t, all a client has 
>> to do to work with it correctly is *not make subclasses*. The library is 
>> still usable. Conversely, if a library mistakenly prohibits subclassing, 
>> then there are things a client *should* be able to do but cannot. The harm 
>> to the users of a library is greater in this last case, because the ability 
>> to use the library is compromised, and that diminishes their productivity.
> 
> If a client uses a library type which was never intended to be subclassed and 
> subclasses it, the only options to take the library forward are to:
> 1. break the client
> 2. make that usage part of your supported API, and work around any issues 
> that causes
> 
> I sympathize with app developers under deadlines. I wouldn’t mind Swift 
> having an ‘escape hatch’ to let an app developer take responsibility and to 
> then abuse a library’s access levels (if that were possible without 
> restricting optimizations in the Swift compiler). But closed-by-default is 
> safer, and lets poorly specified libraries evolve to be higher quality 
> libraries without breaking existing usage that they never intended to support.
> 
>> We should not make “soft defaults” that tend to negatively impact the 
>> clients of a library for the dubious benefit of enabling its author to 
>> procrastinate on a basic design decision. If someone truly wants to publish 
>> a library with a closed class, then we should support that. But it should be 
>> an intentional decision, not a default.
> 
> If you were proposing the default for public classes be final rather than 
> closed, I would be on-board with that line of thinking.
> 
> If you proposed that final was redundant and should go away, leaving just 
> public and public open, I’d find that defensible (I think even with closed as 
> a default, it is useful to indicate within am module that a class is 
> subclassed or not) 
> 
> If you proposed that library authors should be forced into a decision, and 
> should get a warning with a default of final until they label public classes 
> as open or final or sealsed, I’d also be on-board with that option.
> 
> However, “open by default” is quite different than “final by default”. The 
> default for structs and enums are final by default. Protocols are 
> implementable, but they by definition should have defined semantics for doing 
> so. Open-by-default subclasses have the potential to be modified in ways you 
> were never expected, then handed back to you. Exposing a class the same way 
> you would expose a struct, enum, or protocol and having it directly impact 
> your resiliency because you forgot to also add “final” is just not as safe. I 
> think the SE-0117 discussion covered this *very* well.
> 
>> Motivation – Rethinking ‘private’
>> 
>> Now let us return to ‘private’, which as discussed earlier should be the 
>> only modifier that is tighter than ‘internal’. The purpose of ‘private’ is 
>> to enable encapsulation of related code, without revealing implementation 
>> details to the rest of the module. It should be compatible with using 
>> extensions to build up types, and it should not encourage overly-long files.
> 
> As said before, I think this is an incorrect conclusion. 
> 
> My personal thinking has been swayed over the last few months, and I’ve gone 
> from vehemently opposing private to seeing merit in it. I believe my 
> opposition was not against scoped private, but that it both kept fileprivate 
> as a required access level and a redundant one, because it was not part of a 
> larger change. 
> 
> Swift need a modifier between private and internal, and “fileprivate” is 
> neither the feature we want, nor the spelling. Fileprivate should have been 
> replaced with a more appropriate access level between private and internal, 
> to represent ‘friend” relationships. I think we may be now looking at doing 
> that, with submodules. 

I would love to hear your feedback on my submodule proposal David!  I believe 
it addresses the use cases you're describing very well.
> 
> My tact is that keywords should first and foremost document developer intent.
> 
> If I were to say which members of a type *should* be private, it would be the 
> members that are not properly designed to uphold class invariance. Allowing 
> access to write a negative integer to a property that should only ever be 
> positive would be a good example. Calling a member without holding a lock or 
> first dispatching onto the right GCD queue would be another.
> 
> In that context, a private which restricts even same-file, build-up 
> extensions could be a positive language feature, because the extensions are 
> being built using the safer interface. This is a trade-off, as some 
> interfaces (NSCoding is a prime example) may require access to members 
> otherwise made private.
> 
>> The natural definition, therefore, is that ‘private’ should mean “visible in 
>> a small group of files which belong together as a unit”. Of course Swift 
>> does not yet have submodules, and is not likely to gain them this year. 
>> However, if we say that each file is implicitly its own submodule unless 
>> otherwise specified, then the model works. In that view, ‘private’ will mean 
>> “visible in this submodule”, and for the time being that is synonymous with 
>> “visible in this file”.
> 
> I think internal is a more appropriate visibility within a submodule.
> 
> -DW
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to