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