[swift-evolution] [swift-evolution-announce] [Review] SE-0159: Fix Private Access Levels

Xiaodi Wu xiaodi.wu at gmail.com
Tue Mar 21 22:16:01 CDT 2017


On Tue, Mar 21, 2017 at 9:38 PM, Matthew Johnson <matthew at anandabits.com>
wrote:

>
> On Mar 21, 2017, at 9:28 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Tue, Mar 21, 2017 at 8:31 PM, Matthew Johnson <matthew at anandabits.com>
> wrote:
>
>>
>>
>> Sent from my iPad
>>
>> On Mar 21, 2017, at 7:40 PM, Xiaodi Wu via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>> On Tue, Mar 21, 2017 at 6:44 PM, Drew Crawford <drew at sealedabstract.com>
>> wrote:
>>
>>> I am confused by this response. An argument in _support_ of new
>>> `private` was that it is more in line with expectations of users coming
>>> from other languages. In other some cases, such an argument might have its
>>> place. However, as others have pointed out on this list, those other
>>> languages don't have facilities like Swift's extensions, and therefore it
>>> was not a very strong argument for new `private` to say that it better
>>> aligns with user expectations coming from other languages.
>>>
>>> The underlying issue here (which I have now identified, thanks!) is what
>>> motivates the use of extensions.  That question predates proposals, but the
>>> Swift book provides the following motivation, which I have numbered for
>>> ease of reference:
>>>
>>> 1. Extensions add new functionality to an existing class, structure,
>>> enumeration, or protocol type.
>>>
>>> 2. This includes the ability to extend types for which you do not have
>>> access to the original source code (known as retroactive modeling).
>>>
>>> 3. Extensions are similar to categories in Objective-C.
>>>
>>> It seems to me this motivation contemplates use “at some distance”, that
>>> is we intend to create some semantically meaningful separation between the
>>> declaration and the extension(s).  If we did not we could use MARK or some
>>> other comment-based scheme to organize our class.
>>>
>>> 2 is explicitly at great distance, so we know the distance motivation is
>>> well within scope.  1 refers to “an existing” type which implies a certain
>>> level of functionality in the unextended type, and not merely a partial
>>> implementation in the unextended type.  The record on 3 is more mixed (ObjC
>>> programmers do occasionally use categories “closely-held” to group a few
>>> methods together).  However ObjC also has the “distance” tradition:
>>> categories cannot introduce new storage even when this is technically
>>> trivial (within the same compilation unit for example), and this tradition
>>> was continued under Swift with the new ABI.
>>>
>>> What I am suggesting is that the primary design purpose of an extension
>>> is to create semantic distance between a declaration and the functionality
>>> being added.
>>>
>>
>> I'm not sure it is necessary for extensions to have a "primary design
>> purpose." They serve many purposes. One use I have for them is as follows:
>>
>> ```
>> struct A {
>>   // Stuff here constitutes the "raison d'etre" for A.
>> }
>>
>> extension A : B {
>>   // In the course of implementing `A`, I have discovered that
>>   // `A` can fulfill the semantic guarantees of `B`, and in fact
>>   // fulfills most of them already.
>>   //
>>   // So, I conform to B, as in so doing there are some practical
>>   // advantages, such as gaining some default implementations.
>>   //
>>   // But, to conform, I may need to implement some methods
>>   // not really essential for a functional `A`, but required nonetheless
>>   // to conform to `B`.
>>   //
>>   // I implement them here in an extension; in so doing, I express
>>   // the idea that I have, after implementing `A`, discovered its
>>   // conformance to `B`, and I am here supplying the remaining
>>   // implementations necessary for that conformance.
>>   //
>>   // That is, if `B` did not exist, neither would these functions here.
>>   // But there may be some requirements of `B` that would be
>>   // implemented in `A` whether or not `B` exists.
>>   // Those are implemented above, in `struct A { ... }`.
>> }
>> ```
>>
>> I find this to be an eloquent way to separate concerns. It is a common
>> pattern encouraged by code I admire written by others more skilled than me
>> in Swift.
>>
>> A mechanism to hide variables from extensions is something that
>>> *furthers* this design goal of extensions, rather than contradicts it.
>>>
>>
>> This, I suppose, is an argument for you to take up with Charles.
>>
>>
>>> I understand that some people use extensions as sort of an imitation
>>> “partial class” but they simply aren’t (no storage) and we should introduce
>>> a new feature if we want to have them.
>>>
>>> A core team member (I'm blanking on who) has pointed out that, in the
>>> end, the only necessary access modifiers are public and not public (spelled
>>> "internal" in Swift).
>>>
>>>
>>> It is not clear to me how this squares with the decision in SE-0025 that
>>> other access modifiers were necessary.  Can you clarify?
>>>
>>
>> Why do you think SE-0025 decided that other access modifiers are
>> necessary? It merely decided that having four was deemed, on balance,
>> superior to having three. But the minimum number of access modifiers is, by
>> definition, two. In the case of Swift those essentially have to be at the
>> module boundary. Anything more finely diced than that and you are balancing
>> expressivity and complexity. I would not be opposed, incidentally, to
>> stripping back access modifiers to two: `internal` (or maybe eliminate that
>> explicit annotation altogether) and `public`.
>>
>> When new `private` and `fileprivate` were shipped, there were numerous
>>> questions asked by users on forums such as Stack Overflow
>>>
>>>
>>> And before they were shipped, there were people asking for a scoped
>>> modifier.
>>>
>>
>> No, I'm not talking about "asking for"; I'm talking about "asking"--as
>> in, "I don't get it, please explain." The point is that the distinction
>> between `private` and `fileprivate` is not an intuitive one.
>>
>>
>>> And when we change them again, what questions will that generate?  So I
>>> don’t see what we are accomplishing with this line of inquiry.
>>>
>>> You see the new access modifiers described, for example, as something
>>> that "take[s] some getting used to." Rather damning as a euphemism, don't
>>> you think?
>>>
>>> Not at all.  We could describe strong typing, or optionals, enums,
>>> pattern matching, etc., in this way.  ARC in particular is “difficult to
>>> teach” but we should not get rid of it, it solves a safety problem.  A
>>> scoped access modifier is similar.
>>>
>>
>> Again, the argument is not that scoped access modifiers have _no_ merits
>> or that it solves _no_ problems; it is that its merits are greatly
>> outweighed by its drawbacks, or that the problems solved are not more
>> pressing than the problems introduced, which include problems in learning
>> and teaching Swift.
>>
>> Swift promises only one type of safety by default: memory safety. ("Swift
>> is a high-performance system programming language. It has a clean and
>> modern syntax, offers seamless access to existing C and Objective-C code
>> and frameworks, and is memory safe by default.")
>>
>> Since ARC helps to deliver two indispensable promises ("seamless access
>> to...Objective-C" and "memory safe by default"), that weighs heavily in its
>> favor despite difficulty of learning and teaching. `fileprivate` is, I
>> think you'll agree, certainly not a clean and modern syntax, and its
>> presence or absence has little to do with the other tentpole promises of
>> Swift.
>>
>> When the Swift core team approved the proposal, they expressed the belief
>>> that `fileprivate` would be rarely used. This has turned out plainly and
>>> indisputably not to be true. It is clear that they expected Swift to have,
>>> after SE-0025 (and before `open`), three commonly used access modifiers and
>>> one vestigial one. Instead we have four/five commonly used access
>>> modifiers. Thus, the complexity of the current system is _not_ what was
>>> envisioned at the time of approval for SE-0025, and the resulting system
>>> should be re-evaluated in light of this real-world data.
>>>
>>> The only citation I can find on this topic is the cryptic “fileprivate
>>> is rarely needed
>>> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160328/013829.html>”
>>> in the context of “rare enough to be explicit”.   I submit that according
>>> to previously-presented data, I do use it rarely, less often than the other
>>> modifiers, certainly in a manner consistent with being explicit.  I do not
>>> see how we jump from that fact pattern to “plainly and indisputably… _not_
>>> what was envisioned at the time”.  It is not plain and I do dispute it.
>>>
>>
>> *You* may indeed write in a style that uses it rarely. I think you see
>> from even this conversation that others do not code in such a style. There
>> are 183,000 results for `fileprivate` on Google, which is in the same
>> ballpark as results for `associatedtype`. Compare with 60,800 for
>> `precedencegroup` and 1430 for `ExpressibleByStringInterpolation`.
>>
>> The code above should compile and does not.
>>>
>>> It is not clear to me how this is especially relevant.  The point of a
>>> scoped access modifier is to prevent programs from compiling when they
>>> should not.  Here is a program that does not compile when it should; that’s
>>> a bug, but it doesn’t go to whether the scoped people are caught with their
>>> pants down or working from bad safety assumptions.  It’s just a complier
>>> crasher.
>>>
>>
>> It is relevant because this is not some corner case; it's not some fuzzed
>> nonsense like `{{<<var;;` that happens to crash the parser. It is a
>> tentpole feature of `private` proposed in SE-0025 that shipped broken in
>> 3.0 and will ship broken in 3.1. In other words, SE-0025 has not been
>> completely implemented, and if ABI stability is declared before it is
>> fixed, it may not even be completely implementable.
>>
>>
>>> (a) even proponents of new `private` disagree on one of two key goals
>>> stated for new `private`;
>>>
>>> I suspect that not everyone will agree on the three stated goals for
>>> extensions either, but I do not with to remove them.
>>>
>> TSPL is not the document of record for goals for extensions, it's a
>> pedagogical tool. By contrast, SE-0025 is the document of record for goals
>> for the new `private`. They may not be *your* goals for `private`, but they
>> are *the Swift community's* goals for `private`, and they have not been met.
>>
>>> I wish to improve them, and a scoped access modifier is one of the tools
>>> we have to do that.
>>>
>>> As far as I can see, in that example, you can rename `private func
>>> prune` to `private func _prune` and have no further problems. That is to
>>> say, the workaround is a single character at each use site, which by your
>>> metric makes this proposal half as onerous as removing `++`.
>>>
>>> The problems are described in SE-0025:
>>>
>>> > Another, less reliable, way is to prefix APIs that are meant to be
>>> hidden with a _ or do something similar. That works, but it’s not enforced
>>> by the compiler, and those APIs show up in tools like code completion, so
>>> the programmer has to filter out the noise — although these tools could
>>> quite easily support hiding methods with the _ prefix standard. Also, there
>>> is a greater danger of using private APIs if they do something similar to
>>> public APIs but are somehow more optimized (because they make additional
>>> assumptions about the internal state).
>>>
>>> In any case, this workaround is not “semantically equivalent” and so
>>> regardless of the number of characters it is different than ++ or var.
>>>
>> I'm not sure how the quotation describes a semantic issue; it describes a
>> practical drawback with respect to code completion. And it's correct.
>> Again, I'm not saying that there are no merits to a scoped access level.
>> I'm just saying that a tidier code completion menu and not writing `_`
>> aren't in themselves compelling. The workaround after removal is totally
>> transparent to the end user, and all uses of a non-public API in the same
>> file can be trivially audited to prove that they aren't called at
>> unintended places, so I'm not sure why you think some bar of "semantic
>> equivalence" needs to be met.
>>
>>
>> Uses in a single file at a single point in time can be audited
>> trivially.  Ensuring correct use  all (scope)private variables in all files
>> of a large project over a span of years is not so trivial.  This kind of
>> mistake can slip through code review even on diligent team.  The compiler
>> guarantee has significant value in these contexts.
>>
>
> Certainly, I'm not arguing that it doesn't have its benefits. But if it
> slips through code review, what goes wrong?
>
>
> Bugs of various sorts.  I have seen this very thing happen recently in
> Swift 2.3 code.
>
> And couldn't this be enforced by a linter feature that warns if a private
> member beginning with _ is accessed outside of scope?
>
>
> I don’t like to use naming conventions and linters to catch things that
> belong in the language proper.  Hasn’t the community agreed that we don’t
> want dialects of Swift?
>

Very agreed. But is it a "dialect" when it's spoken by the standard library?


>
>
>
>>
>>> On March 21, 2017 at 5:26:47 PM, Xiaodi Wu (xiaodi.wu at gmail.com) wrote:
>>>
>>> On Tue, Mar 21, 2017 at 3:59 PM, Drew Crawford via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>>  The arguments for the revert are in the proposal and in the
>>>> discussions in this thread.
>>>>
>>>>
>>>> What is in the proposal and this thread are a set of opinions, e.g.
>>>>
>>>> * "the access level change of SE-0025 was met with dissatisfaction by a
>>>> substantial proportion of the general Swift community."
>>>> * "Those changes can be viewed as actively harmful,”
>>>> * "it is extremely common to use several extensions within a file.”
>>>> * “[existing regime] encourages overuse of scoped access control”
>>>> * “[fileprivate is the] more reasonable default”
>>>>
>>>> I am asking for the arguments or evidence that led you or others to
>>>> these opinions.  I understand that you and others believe them, but you
>>>> understand that they are now a matter of debate. We are not going to reach
>>>> any mutual understanding just asserting things we believe.  The underlying
>>>> evidence is what would be necessary to convince others to our point of
>>>> view.  I am trying to ascertain what that evidence is.
>>>>
>>>> > It has pointed quite a few times by core team members that comparison
>>>> to languages is not a very strong arguments,
>>>>
>>>>
>>>> The context here is that you presented an argument that Swift’s
>>>> “private” was confusing to users of other languages:
>>>>
>>>> > In most languages, that keyword is “private” so its valid to say that
>>>> newcomers to the language will “default” to using that one.
>>>>
>>>> If you no longer think that argument is strong because it relies on a
>>>> comparison to other languages, then we agree :-)  But in that case we lose
>>>> an argument for this proposal.  The reason we are talking about other
>>>> languages is because that was an argument advanced to support the proposal.
>>>>
>>>>
>>> I am confused by this response. An argument in _support_ of new
>>> `private` was that it is more in line with expectations of users coming
>>> from other languages. In other some cases, such an argument might have its
>>> place. However, as others have pointed out on this list, those other
>>> languages don't have facilities like Swift's extensions, and therefore it
>>> was not a very strong argument for new `private` to say that it better
>>> aligns with user expectations coming from other languages.
>>>
>>>
>>>> > Some people used the for(;;) loop, the ++ operator, var parameters.
>>>>
>>>>
>>>> In those cases, there was extensive discussion of how to achieve the
>>>> things people were achieving with those features with alternative patterns.
>>>> var parameters for example have a 1LOC workaround to achieve the previous
>>>> semantics, ++ had two characters, for(;;) was slightly trickier but we had
>>>> a clear concept of the scope of the impact. So far as I’m aware, the only
>>>> suggestion to people who currently use a scoped access modifier is to stop
>>>> having their problems.
>>>>
>>>
>>> You've given one example of code that takes advantage of new `private`.
>>> As far as I can see, in that example, you can rename `private func prune`
>>> to `private func _prune` and have no further problems. That is to say, the
>>> workaround is a single character at each use site, which by your metric
>>> makes this proposal half as onerous as removing `++`.
>>>
>>> So the circumstances of earlier removals and this one are very different.
>>>>
>>>> > • either a programmer ... will use private as often as possible
>>>> > • or a programmer will … use fileprivate all the time
>>>>
>>>> There is also the possibility that a programmer considers which
>>>> modifier is appropriate for the code they are writing.  You "argue that...
>>>> is very rare” but I still am not sure what this argument is or what led you
>>>> or others to this conclusion.
>>>>
>>>
>>> I'm not enamored of the argumentation in the proposal set out above. But
>>> since you are saying that you're not sure how anybody came to support this
>>> proposal, here's how I arrived at supporting it:
>>>
>>> A core team member (I'm blanking on who) has pointed out that, in the
>>> end, the only necessary access modifiers are public and not public (spelled
>>> "internal" in Swift). It has been my understanding that supporting all
>>> possible ways of hiding a member from arbitrary other code within the same
>>> module is a _non-goal_. There have been numerous attempts at designing
>>> elaborate access modifier schemes that make this possible with friends,
>>> protected, shared, what-have-you, and I try to bring up this point each
>>> time.
>>>
>>> Beyond the two absolutely essential access modifiers, anything else does
>>> not add to safety as the term is understood in Swift, but rather improves
>>> developer experience. But what is gained in terms of developer experience
>>> with each additional access modifier (due to increased expressiveness) is
>>> offset by what is lost due to complexity. So then the question is: what is
>>> the ideal number of access modifiers? is it two? three? four? five? six?
>>> eight? ten? twelve?
>>>
>>> When new `private` and `fileprivate` were shipped, there were numerous
>>> questions asked by users on forums such as Stack Overflow (easily googled;
>>> just as a single example: http://stackoverflow.
>>> com/questions/39027250/what-is-a-good-example-to-differentia
>>> te-between-fileprivate-and-private-in-swift), on blogs (again, easily
>>> googled; as a single example: https://useyourloaf.c
>>> om/blog/swift-3-access-controls/), and messages to this list (including
>>> from people not part of the original discussion but who, on using the
>>> feature, found it irksome enough to join the list and make their voice
>>> heard).
>>>
>>> You see the new access modifiers described, for example, as something
>>> that "take[s] some getting used to." Rather damning as a euphemism, don't
>>> you think? Certainly not a ringing endorsement--
>>>
>>> "How do you like my new haircut?"
>>> "It, um, takes some getting used to."
>>>
>>> Others also wrote to say that they were finding it difficult to *teach*
>>> this new scheme to students; you can find such messages in the list
>>> archives. I take this to mean that having four/five access modifiers
>>> (depending on whether you consider `open` to be an access modifier) to be
>>> one too many.
>>>
>>> When the Swift core team approved the proposal, they expressed the
>>> belief that `fileprivate` would be rarely used. This has turned out plainly
>>> and indisputably not to be true. It is clear that they expected Swift to
>>> have, after SE-0025 (and before `open`), three commonly used access
>>> modifiers and one vestigial one. Instead we have four/five commonly used
>>> access modifiers. Thus, the complexity of the current system is _not_ what
>>> was envisioned at the time of approval for SE-0025, and the resulting
>>> system should be re-evaluated in light of this real-world data.
>>>
>>> So, if four/five access modifiers are too many, which one is carrying
>>> the least weight? Which one could be removed to simplify the scheme while
>>> maintaining the most expressiveness? Which one doesn't fulfill even its own
>>> stated goals? Well, one of the key goals of `private` was to allow members
>>> to be encapsulated within an extension, hidden even from the type being
>>> extended (and vice versa for members defined in the type). It says so in
>>> the first sentence of SE-0025. As seen above in my discussion with Charles
>>> Srstka, even supporters of `private` disagree with that motivation to begin
>>> with. The kicker is, _it also doesn't work_. Try, for instance:
>>>
>>> ```
>>> struct Foo {
>>>   private var bar: Int { return 42 }
>>> }
>>>
>>> extension Foo {
>>>   private var bar: Int { return 43 }
>>> }
>>> ```
>>>
>>> The code above should compile and does not. If I understood correctly
>>> the explanation from a core team member on this list, it's unclear if it
>>> can be made to work without changing how mangling works, which I believe
>>> impacts ABI and is not trivial at all. Thus, (a) even proponents of new
>>> `private` disagree on one of two key goals stated for new `private`; (b)
>>> that goal was never accomplished, and making it work is not trivial; (c) no
>>> one even complained about it, suggesting that it was a low-yield goal in
>>> the first place.
>>>
>>> So, I conclude that new `private` needs re-evaluation in light of
>>> real-world implementation and usage experience. I haven't even mentioned
>>> the nuances of `private` in one scope being different from `private` in the
>>> containing scope, requiring distinguishing of effective access levels from
>>> nominal ones--just one more wrinkle in this whole scheme. I feel that
>>> allowing someone to write `private var foo` instead of `private var _foo //
>>> don't call this outside the type`, when that member isn't vended and can't
>>> be seen outside the file anyway, is a tiny win in comparison to the huge
>>> complexity both of implementation (it's still not correctly implemented and
>>> may not be in time for Swift 4!!!) and of usage.
>>>
>>>
>>> On March 21, 2017 at 1:41:48 PM, David Hart (david at hartbit.com) wrote:
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> Sent from my iPhone
>>>> On 21 Mar 2017, at 16:57, Drew Crawford <drew at sealedabstract.com>
>>>> wrote:
>>>>
>>>>
>>>>
>>>> > I’m not arguing that it is less or more than a majority. I’m just
>>>> saying that we’ve seen a lot of talk against the original change.
>>>>
>>>> This proposal asks us to balance the convenience of one group
>>>> (extension-writers) against the existence of another (scoped-access
>>>> users).  To do that, we need a clear idea of the composition of both groups.
>>>>
>>>> “A lot of talk” is not the evidentiary standard to remove a feature.
>>>> It was not good enough when we introduced the feature, that required
>>>> argument and clear use-cases.
>>>>
>>>> "A lot of talk" is not the evidence supporting the proposal: it's just
>>>> a warning that something may be very controversial among the community. The
>>>> arguments for the revert are in the proposal and in the discussions in this
>>>> thread.
>>>>
>>>> > By default, I did not mean the syntactic default of the language but
>>>> the access modifier users will use “by default” when trying to restrict
>>>> visibility. In most languages, that keyword is “private” so its valid to
>>>> say that newcomers to the language will “default” to using that one.
>>>>
>>>> Apologies, but I do not understand the argument:
>>>>
>>>>    1. A user wants to restrict visibility (e.g. they are dissatisfied
>>>>    with “internal”)
>>>>    2. The user *chooses* private because of familiarity from another
>>>>    language
>>>>    3. The user is then surprised that their choice of private indeed
>>>>    restricted the visibility, thus achieving their goal?
>>>>
>>>> What language does the user come from in which “private” is
>>>> file-visible?  It isn’t Java, C++, or PHP.  C#’s “partial” is the closest I
>>>> can think of, and it isn’t at all close.
>>>>
>>>>
>>>> It has pointed quite a few times by core team members that comparison
>>>> to languages is not a very strong arguments, especially when Swift does
>>>> things differently for a good reason. I can't stop from quoting Xiaodi from
>>>> a month back:
>>>>
>>>> «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.» -- Xiaodi
>>>>
>>>> A user who wants a middle-ground visibility would “default” to
>>>> “protected”, “friend”, “partial”, or similar.  After that does not compile,
>>>> they will use google to find a middle-road visibility keyword, for which
>>>> the only candidate is “fileprivate”.  But they will not choose “private”,
>>>> it’s just not a reasonable expectation of what the keyword means to a new
>>>> Swift developer.
>>>>
>>>> The popularity of private “as a default” is simply because many users
>>>> prefer to hide their implementation details as a matter of routine code
>>>> hygiene.  Redefining private in order to thwart their code hygiene goal
>>>> seems extreme.
>>>>
>>>>
>>>> The point is that keeping both private and fileprivate feels like an
>>>> un-necessary complication:
>>>>
>>>> • either a programmer falls on your side of the fence and will use
>>>> private as often as possible and relegate to fileprivate when the design
>>>> leaves no other choice. At that point it feels like a language wart.
>>>> • or a programmer will fall on my side of the fence and use fileprivate
>>>> all the time and the language feels like it has an unnecessary access
>>>> modifier.
>>>>
>>>> I'd argue that the cases when a programmer will use both meaningfully
>>>> is very rare. As a consequence, we should try to only keep one. Removing
>>>> fileprivate is a no-go with extensions so that leaves us with removing
>>>> private.
>>>>
>>>> I agree with several here (as I did in SE-0025) that our access
>>>> modifiers are not well-named.  However, that’s not the proposal in front of
>>>> us.
>>>>
>>>> > My own statistics in my projects show the contrary. At best, this
>>>> shows how divisive this feature is.
>>>>
>>>> This *may* show that, if contrary statistics were presented, but that
>>>> hasn’t occurred.
>>>>
>>>> I can generate statistics from my projects if you want. But it's
>>>> unnecessary: I haven't used private once since it's introduction in Swift
>>>> 3. I don't see the advantages it brings worth the trouble.
>>>>
>>>>
>>>>    - In old code, statistics could be biased by the migrator having
>>>>    replaced all previous instances of private by fileprivate.
>>>>
>>>> If the migrator migrated code to private, and it *worked* (e.g. did not
>>>> introduce visibility errors) this is not bias, this is a correct use of the
>>>> feature.
>>>>
>>>> The migrator migrated to fileprivate everywhere, not private,
>>>> disagreeing with your use of fileprivate.
>>>>
>>>> > I'm just arguing that the additional scope-based access modifier does
>>>> not provide enough differentiation to be worth that complexity.
>>>>
>>>> The only argument I have seen so far around “complexity” boils down to:
>>>> “some people do not use it”.  But some people *do* use it, and anyway if we
>>>> are going to remove all the features “not enough people” use then we are in
>>>> for a ride.
>>>>
>>>> Some people used the for(;;) loop, the ++ operator, var parameters.
>>>> Many other features were removed from Swift to simplify he language, make
>>>> it more consistent. Those are worthwhile goals. Yes, we are past Swift 3
>>>> now, but that doesn't mean we shouldn't be able to propose a few rare
>>>> breaking proposals. The implementation of access modifiers came so late in
>>>> the Swift 3 timeframe that we had little time to play around with them
>>>> before Swift 3 was released. Now that we have, we have a short window of
>>>> time to fix mistakes that were made. I'm just arguing that the proposal was
>>>> one of those mistakes. But you have a right to disagree.
>>>>
>>>> Swift 3 shipped, so what we are discussing now is yanking a keyword
>>>> without replacement.  There is code written that uses private to enforce
>>>> its threading or security invariants.  There is code written that uses
>>>> private in order to shadow another declaration.   There is code that will
>>>> not compile after migration. We need more than a vague fear of complexity
>>>> generally to throw a brick through all those windows.  That brick will
>>>> introduce quite a bit of complexity itself.
>>>>
>>>> Concerning the one-class-per-file argument, I would suggest this
>>>> counter-argument: when working in large projects, I believe it's a good
>>>> thing if the language encourages (forces is too strong a word for my taste)
>>>> a one class per file structure, it's good practice.
>>>>
>>>>
>>>> The form of the argument is invalid.  Suppose I argued: "it’s a good
>>>> thing for the language to encourage one definition per class (no
>>>> extensions), it’s good practice.  So we do not need fileprivate.”  That
>>>> would be very silly (although it has already been advanced as a straw-man
>>>> position elsewhere in this thread). The argument that we do not need
>>>> private because nobody should put multiple classes in a file is equally
>>>> silly. There are reasons to do so, in fact one motivation was given in
>>>> SE-0025:
>>>>
>>>> > Putting related APIs and/or related implementations in the same file
>>>> helps ensure consistency and reduces the time to find a particular API or
>>>> implementation.
>>>>
>>>>
>>>> These concerns are not resolved by arguments of the form “just don’t do
>>>> that”.
>>>>
>>>> I empathize with the Swift2 programmer who got through two releases
>>>> without a scoped access modifier and is annoyed by change.  However,
>>>> removing the feature now is more change, not less, so it makes their
>>>> problem worse, not better.
>>>>
>>>>
>>>> On March 21, 2017 at 2:17:40 AM, David Hart (david at hartbit.com) wrote:
>>>>
>>>> Perhaps it was a mistake, but I purposefully did not go into too much
>>>> detail in the proposal because I think this debate is purely a question of
>>>> philosophy on Swift and its language features. I did not want to add
>>>> un-necessary bloat that would have added little rationalisation. Let me try
>>>> to explain the holes in the proposal by answering your review:
>>>>
>>>> On 21 Mar 2017, at 02:26, Drew Crawford via swift-evolution <
>>>> swift-evolution at swift.org> wrote:
>>>>
>>>> I disagree quite strongly with the proposal.
>>>>
>>>> First, the document draws conclusions without apparent supporting
>>>> evidence, e.g.
>>>>
>>>> > Since the release of Swift 3, the access level change of SE–0025 was
>>>> met with dissatisfaction by a substantial proportion of the general Swift
>>>> community. Those changes can be viewed as actively harmful, the new
>>>> requirement for syntax/API changes.
>>>>
>>>>
>>>>    - What is “dissatisfaction by a substantial proportion of the
>>>>    general Swift community”? How was this measured/determined?
>>>>
>>>> It’s not feasible to measure precisely the feeling of a whole
>>>> community. But we get a feeling for it by following the mailing-list, by
>>>> talking to colleagues, by reading twitter, etc… And it think we all agree
>>>> that the debate is highly divisive and that a “substantial proportion” of
>>>> the community was dissatisfied: I’m not arguing that it is less or more
>>>> than a majority. I’m just saying that we’ve seen a lot of talk against the
>>>> original change.
>>>>
>>>>
>>>>    - What was done to control for the population happy with SE-0025
>>>>    who would e.g. not be likely to take up pitchforks?
>>>>
>>>> That’s why its important we have this debate now.
>>>>
>>>>
>>>>    - Who argues these changes are “actively harmful” and where were
>>>>    they during SE-0025?
>>>>
>>>> The proposal makes the argument that the changes are actively harmful.
>>>> It’s now up to debate. By the way, even if several people (including me)
>>>> were already against this proposal during the review, I don’t see why
>>>> anybody would not have the right to change his mind, especially after
>>>> several months of production usage and argue differently now.
>>>>
>>>> > subtly encourages overuse of scoped access control and discourages
>>>> the more reasonable default
>>>>
>>>>
>>>>    - Who claims that scoped access is “overused” and what is their
>>>>    argument for doing so?
>>>>    - Why is “fileprivate” the “more reasonable default”? In fact
>>>>    neither fileprivate **nor** private are default (reasonable or
>>>>    not!). Internal is the default. Nor does this proposal suggest we change
>>>>    that. So this seems a very strange statement.
>>>>
>>>> By default, I did not mean the syntactic default of the language but
>>>> the access modifier users will use “by default” when trying to restrict
>>>> visibility. In most languages, that keyword is “private” so its valid to
>>>> say that newcomers to the language will “default” to using that one. If the
>>>> proposal is accepted, file-scoped private will regain that status.
>>>>
>>>> > But is that distinction between private and fileprivate actively used
>>>> by the larger community of Swift developers?
>>>>
>>>> Yes. To cite some evidence, here are codebases I actively maintain:
>>>>
>>>> | codebase                                               | private # |
>>>> fileprivate # | ratio |
>>>>
>>>> |--------------------------------------------------------|--
>>>> ---------|---------------|-------|
>>>>
>>>> | "M" (proprietary)                                      | 486       |
>>>> 249           | 2x    |
>>>>
>>>> | "N"(proprietary)                                       | 179       |
>>>> 59            | 3x    |
>>>>
>>>> | NaOH https://code.sealedabstract.com/drewcrawford/NaOH | 15        |
>>>> 1             | 15x   |
>>>>
>>>> | atbuild https://github.com/AnarchyTools/atbuild        | 54        |
>>>> 5             | 11x   |
>>>>
>>>> So from my chair, not only is the distinction useful, but scoped access
>>>> control (private) is overwhelmingly (2-15x) more useful than fileprivate.
>>>>
>>>> My own statistics in my projects show the contrary. At best, this shows
>>>> how divisive this feature is. During the discussion of this proposal, it
>>>> was argued that making decisions based upon project statistics would be
>>>> dangerous:
>>>>
>>>>
>>>>    - In old code, statistics could be biased by the migrator having
>>>>    replaced all previous instances of private by fileprivate.
>>>>    - In new code, satistics could be biased by people using private
>>>>    because of it being the “soft-default”, regardless of proper semantics.
>>>>
>>>> > And if it were used pervasively, would it be worth the cognitive load
>>>> and complexity of keeping two very similar access levels in the language?
>>>> This proposal argues that answer to both questions is no
>>>>
>>>> This proposal does not make any later argument about “cognitive load”
>>>> or “complexity” I can identify.  Did the proposal get truncated?
>>>>
>>>> Sorry if I did not state it explicitly, but I see any feature/keyword
>>>> added to the language as “additional complexity”. And that complexity is
>>>> completely worth it when the feature adds significant expressivity. I'm
>>>> just arguing that the additional scope-based access modifier does not
>>>> provide enough differentiation to be worth that complexity.
>>>>
>>>> What is stated (without evidence) is that "it is extremely common to
>>>> use several extensions within a file” and that use of “private” is annoying
>>>> in that case.  I now extend the above table
>>>>
>>>> | codebase                                               | private # |
>>>> fileprivate # | ratio | # of extensions (>=3 extensions in file) |
>>>>
>>>> |--------------------------------------------------------|--
>>>> ---------|---------------|-------|--------------------------
>>>> ----------------|
>>>>
>>>> | "M" (proprietary)                                      | 486       |
>>>> 249           | 2x    | 48                                       |
>>>>
>>>> | "N"(proprietary)                                       | 179       |
>>>> 59            | 3x    | 84                                       |
>>>>
>>>> | NaOH https://code.sealedabstract.com/drewcrawford/NaOH | 15        |
>>>> 1             | 15x   | 3                                        |
>>>>
>>>> | atbuild https://github.com/AnarchyTools/atbuild        | 54        |
>>>> 5             | 11x   | 6                                        |
>>>>
>>>> in order to demonstrate in my corner of Swift this is not “extremely
>>>> common”, and is actually less popular than language features the proposal
>>>> alleges aren’t used.
>>>>
>>>> My point here is that ***different people in different corners of the
>>>> community program Swift differently and use different styles***.  I
>>>> can definitely empathize with folks like the author who use extensions to
>>>> group functions and are annoyed that their favorite visibility modifier
>>>> grew four extra characters.  Perhaps we can come up with a keyword that is
>>>> more succint.
>>>>
>>>> I agree that different people in different corners use different
>>>> styles. But you could use that argument to validate many features which
>>>> would make a group of users happy; but all those feature together would
>>>> just add bloat to the language. Swift has been known to be a very
>>>> opinionated language, to keep the language simple yet expressive.
>>>>
>>>> However, that is no reason to take away features from working
>>>> codebases.  A scoped access modifier is perhaps my favorite feature in
>>>> Swift 3.  Let’s not throw stuff away because it adds extra characters to
>>>> one programming style.
>>>>
>>>> Finally, SE-0025 establishes clear motivation for the scoped access
>>>> modifier:
>>>>
>>>> > Currently, the only reliable way to hide implementation details of a
>>>> class is to put the code in a separate file and mark it as private. This is
>>>> not ideal for the following reasons:
>>>>
>>>> > It is not clear whether the implementation details are meant to be
>>>> completely hidden or can be shared with some related code without the
>>>> danger of misusing the APIs marked as private. If a file already has
>>>> multiple classes, it is not clear if a particular API is meant to be hidden
>>>> completely or can be shared with the other classes.
>>>>
>>>> > It forces a one class per file structure, which is very limiting.
>>>> Putting related APIs and/or related implementations in the same file helps
>>>> ensure consistency and reduces the time to find a particular API or
>>>> implementation. This does not mean that the classes in the same file need
>>>> to share otherwise hidden APIs, but there is no way to express such
>>>> sharability with the current access levels.
>>>>
>>>> As far as I can see, the proposal does not actually address or
>>>> acknowledge these problems at all, but cheerfully returns us to them.  It
>>>> would be a mistake to deprecate this feature without examining at all why
>>>> we introduced it.  And realistically we need new solutions to those
>>>> problems before removing the existing one.
>>>>
>>>> Drew
>>>>
>>>> On March 20, 2017 at 6:54:55 PM, Douglas Gregor (dgregor at apple.com)
>>>> wrote:
>>>>
>>>> Hello Swift community,
>>>>
>>>> The review of SE–0159 “Fix Private Access Levels” begins now and runs
>>>> through March 27, 2017. The proposal is available here:
>>>>
>>>> https://github.com/apple/swift-evolution/blob/master/proposa
>>>> ls/0159-fix-private-access-levels.md Reviews are an important part of
>>>> the Swift evolution process. All reviews should be sent to the
>>>> swift-evolution mailing list at
>>>>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution or, if you
>>>> would like to keep your feedback private, directly to the review manager.
>>>> When replying, please try to keep the proposal link at the top of the
>>>> message:
>>>>
>>>> Proposal link:
>>>>
>>>> https://github.com/apple/swift-evolution/blob/master/proposa
>>>> ls/0159-fix-private-access-levels.md Reply text Other replies What
>>>> goes into a review?
>>>>
>>>> The goal of the review process is to improve the proposal under review
>>>> through constructive criticism and, eventually, determine the direction of
>>>> Swift. When writing your review, here are some questions you might want to
>>>> answer in your review:
>>>>
>>>> What is your evaluation of the proposal? Is the problem being addressed
>>>> significant enough to warrant a change to Swift? Does this proposal fit
>>>> well with the feel and direction of Swift? If you have used other languages
>>>> or libraries with a similar feature, how do you feel that this proposal
>>>> compares to those? How much effort did you put into your review? A glance,
>>>> a quick reading, or an in-depth study? More information about the Swift
>>>> evolution process is available at
>>>>
>>>> https://github.com/apple/swift-evolution/blob/master/process.md Thank
>>>> you,
>>>>
>>>> -Doug
>>>>
>>>> Review Manager
>>>> ------------------------------
>>>>
>>>> swift-evolution-announce mailing list swift-evolution-announce@
>>>> swift.org https://lists.swift.org/mailman/listinfo/swift-evo
>>>> lution-announce
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>>
>>>
>> _______________________________________________
>> 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/20170321/376c97a1/attachment.html>


More information about the swift-evolution mailing list