Sent from my iPad

> On Mar 26, 2017, at 8:44 PM, Brent Royal-Gordon <[email protected]> 
> wrote:
> 
>> On Mar 26, 2017, at 10:43 AM, Matthew Johnson via swift-evolution 
>> <[email protected]> wrote:
>> 
>>> On Mar 26, 2017, at 10:43 AM, Xiaodi Wu <[email protected]> wrote:
>>> 
>>> This reaches the crux of the issue, doesn't it? The Swift 2 design for 
>>> access modifiers does exactly what you reject: that design is based on the 
>>> premise that it is wise for file organization to follow encapsulation.
>> 
>> It's always a gamble speculating about the premise of someone else's design. 
>>  That said, if I had to guess I would imagine maybe it had as much to do 
>> with the legacy of C-family languages and header files as anything else.
> 
> 
> I've seen people say this several times in access control threads, but 
> personally, I don't think the use of files for access control is a "legacy" 
> or a coincidence. I think it's a pretty smart move.
> 
> By its nature, the `internal` scope is already defined by files: There is a 
> certain set of files which are compiled together to form the module, and 
> those files all see the same `internal` scope. Unless we entirely abandon the 
> idea of Swift as a fully textual language and move to a FoxPro-style system 
> where code is stored in a structured database, this will always be true in 
> Swift. I have a hard time imagining an environment for writing Swift code 
> where there *aren't* files or some equivalent named-chunk-of-arbitrary-code 
> unit of organization like the "pages" in a playground.
> 
> Using files to scope `private` is thus a natural extension of the `internal` 
> scope's rules (one group of files defines the `internal` scope; one single 
> file defines the `private` scope). It also happens to fit well with typical 
> programmer behavior. Organizing your code into files by concern is generally 
> considered a best practice, but files do not carry any other semantic 
> meaning: there's nothing (else) in the language that forces you to put a 
> given declaration in one file or another. So with file-based `private`, there 
> are only two reasons to care about which file a piece of code is in—`private` 
> access and subjective code organization—and these two things are usually 
> aligned.

They're usually aligned at one level of granularity but often not at another.  
Small helper types are subjectively best placed in the same file as the type 
they are assisting yet there are still good reasons to encapsulate their state. 
 Further, they should not be visible beyond the code they are helping.  

Even if you can properly encapsulate everything as desired using separate files 
and submodules you are left with code organization that subjectively and 
pragmatically is suboptimal.  I don't want a bunch of files with 20 line helper 
types in my project.  This leads to way too much file switching which 
significantly reduces clarity. 

> 
> This point is actually implicitly acknowledged by, for instance, the 
> submodule proposal Jonathan Hull put forth upthread, where each file is 
> implicitly its own submodule if not declared to be part of a different one. 
> Files aren't always the right encapsulation boundary, but they often are.

I agree that files are often the right boundary for encapsulation and have not 
argued against allowing us to address file scopes (unless of course we get a 
submodule solution that makes them redundant).  I also agree that using groups 
of files to organize code into submodules makes a lot of sense.

My point is simply that there is nothing inevitable about using them as an 
access control boundary.  There are tradeoffs involved.  Having files be the 
largest addressable scope smaller than the module is largely responsible for 
the long file problem in Swift code.  Certainly far more responsible than 
scoped access control.  (This point was made in response to John's reference to 
10,000 line files).

I have nothing at all against all the uses of files you describe above.  I just 
don't think files are the answer to every use case for access control.  There 
are strong pragmatic reasons for allowing encapsulation of types within a file. 
 

> 
> What *can't* file-based organization do, but explicit or implicit scope 
> boundaries can? Well, they can't nest. But as I've previously argued, 
> limiting access to the confines of a nested scope is often problematic 
> because you can only address the current scope, not a surrounding scope;

This is not an inevitable state of affairs.  Again we have a tradeoff and could 
allow addressing containing scopes if desired.  But let's not have that debate 
right now.

For scopes smaller than a file, the current scope is by far the most useful one 
to address.  It is the one that we must be able to address to protect access to 
the state of helper types or small types that closely collaborate.  In cases 
where this kind of tight encapsulation isn't necessary "oversharing" isn't 
nearly as big a deal in cases I've run across.  

> thus, sharing even one level up requires you to "overshare" with the entire 
> file or even (if there's no `fileprivate`) the entire module. Unless you 
> start building `friend`-like features, of course, but I believe John McCall 
> already discussed why that's a bad idea:

I don't recall anyone advocating for `friend` or anything along those lines.  I 
agree that would be a bad idea.

> 
>> access control is never going to be sufficiently expressive to express 
>> constraints like "this method can only be called from this other method" — 
>> we actively would not want to encourage programmers to engage in that level 
>> of pedantry, because some of them will, and they'll make themselves 
>> miserable and accomplish nothing of value, and they'll blame Swift 
>> (correctly) for implying that it was important.
> 
> 
> We could, of course, introduce some kind of explicit declaration for private 
> scopes. But why? Files usually match or at least approximate the desired 
> boundaries

This is true much of the time, but there are a very meaningful number of cases 
where it is not true.

> , and when they don't already, they usually can be made to do so.

This is simply not true today.  When I have a small helper type T that should 
only be visible to type U they must be in the same file.  This necessarily 
means that without scoped access T cannot hide any details from U.  This is not 
at all uncommon in projects I have work on.

It might be true with submodules in the future.  But we don't yet know what the 
future holds and we're debating a proposed change to the language that will 
happen long before that future.

> Sometimes they can't, but that merely means you have to be careful. How much 
> syntax should we really dedicate to a corner case, especially one that 
> doesn't prevent anything from being written, but merely requires you to 
> exercise caution?

I don't consider this to be a corner case.  It impacts a very meaningful 
percentage of the code I write.  I really don't think one access modifier is 
too much to ask here.

One of the reasons I like Swift so much is that in most cases when the language 
can help catch mistakes at compile time it does that.  The community generally 
values this greatly.

I have learned over the years that no matter how cautious I am I still make 
mistakes.  I would prefer to have the compiler catch this kind of mistake 
immediately rather than relying on a human to eventually notice the mistake.

Moving the burden of catching these mistakes from the compiler back to humans 
would be a change that is actively harmful IMO.

> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> 
> 
> P.S. Unless I misunderstand your meaning, I believe that this statement in 
> your later post:
> 
>> The implicit outer scope at the file boundary is one that only exists 
>> because it was introduced in Swift 2.
> 
> Is anti-historical. The file scope is as old as `private` (and access 
> control) in Swift, which was part of Swift 1 beta 4: 
> <https://developer.apple.com/swift/blog/?id=5>

Well that was an embarrassing mistake!  I remembered it not being in the 
original release but apparently had forgotten that it was added during the 
Swift 1 beta cycles.  I should have checked before posting.  Thanks for the 
correction.  

> 
> 
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to