[swift-evolution] [Proposal][Discussion] Modular Swift
Matthew Johnson
matthew at anandabits.com
Tue Feb 21 22:59:06 CST 2017
> On Feb 21, 2017, at 10:41 PM, Robert Widmann <devteam.codafi at gmail.com> wrote:
>
> By API boundaries I mean both the one internal to MyModule.Foo and the one defined by MyModule. Here “the API boundary” is explicitly about the submodule MyModule.Foo, whose internal state may have been “unsealed” in the top level by the extension, but has not been re-exported.
I’m sorry, but I just don’t understand how modules form an API boundary in this system. To me a boundary means something that blocks access. In this system `internal` ranges over the entire module and all submodules. The only boundaries I can see besides the module itself are files and lexical scopes (with `fileprivate` and `private`).
This means that it is trivial to put code anywhere within the module that extends the submodule and wraps a symbol in a new name and declares it `public`. They can also trivially add a `public import MyModule.Foo` anywhere at the top level of their file because every file is forced to include top level scope.
In my opinion, we need to identify what goals we have for a submodule system - what problems are we trying to solve and what use cases do we intend to enable.
There are quite a few of us who want the ability to form solid API boundaries inside a module and view this as one of the fundamental features of a submodule system. It’s reasonable to ask why we view this capability as essential.
I can’t speak for anyone else, but here are a few reasons why it’s important to me:
* Solid API boundaries are essential to good design.
* Having access to an entire code base does not reduce the benefits of #1. Some code bases are substantial in size and hard boundaries are important to keeping them manageable.
* Using full-fledged modules to do this is possible, but also involves a bit of ceremony that is incidental, not essential complexity in many cases. It would be better to have a lighter weight mechanism to do this.
* Swift currently only has whole module optimization, not whole program optimization. There is a performance penalty to using full-fledged modules.
>
> ~Robert Widmann
>
>> On Feb 21, 2017, at 11:38 PM, Matthew Johnson <matthew at anandabits.com> wrote:
>>
>>
>>> On Feb 21, 2017, at 10:29 PM, Robert Widmann <devteam.codafi at gmail.com> wrote:
>>>
>>> This level of access, the “private to this submodule except to the select set of interfaces I want to see it” level, is the equivalent of friend classes in C++. I don’t consider leaving this out to be a hole, nor is it an "encapsulation-related problem” because at no point can you break the API boundary and re-export anything here with a higher level of access than it had previously.
>>
>> By API boundary you mean the top-level module, right?
>>
>>>
>>>> On Feb 21, 2017, at 11:13 PM, Matthew Johnson <matthew at anandabits.com> wrote:
>>>>
>>>>
>>>>> On Feb 21, 2017, at 10:11 PM, Matthew Johnson <matthew at anandabits.com> wrote:
>>>>>
>>>>>
>>>>>> On Feb 21, 2017, at 9:47 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
>>>>>>
>>>>>>> On Feb 21, 2017, at 7:38 PM, Robert Widmann <devteam.codafi at gmail.com> wrote:
>>>>>>>
>>>>>>> Correct. Because, in dividing the submodule across an extension, you have placed what should be a private API into a differently-scoped location.
>>>>>>
>>>>>> Okay. So is your submodule design not intended to address the "I want to encapsulate implementation details so they're only visible to several units of code in different files, but not the entire module" use case? Because if there's no way to scope a symbol to "everything inside this submodule, but nothing outside this submodule", I think it leaves that use case unserved.
>>>>>
>>>>> Unless I’m missing something there is also another encapsulation-related problem with the proposed design. Let’s suppose for the sake of discussion there was a `submoduleprivate` access modifier (intentionally ungainly and not realistic).
>>>>>
>>>>> // File 1
>>>>> module Foo {
>>>>> // internal, visible to the whole module
>>>>> class Bar { submoduleprivate var protectedState: Int = 0 }
>>>>> }
>>>>>
>>>>> // File 2 - Has nothing to do with Foo at all
>>>>> import MyModule.Foo
>>>>>
>>>>> module NotFoo {
>>>>> // Hey, I need to see Bar.protectedState!!!
>>>>> func totallyNotFoo() {
>>>>> var bar = Bar()
>>>>> bar.foosExposedPrivates = 42
>>>>> }
>>>>> }
>>>>>
>>>>> // ok, I’ll just add an extension to Foo so I can see submoduleprivate and wrap what I need
>>>>> module Foo {
>>>>
>>>> Oops, this should have been `extension Foo`, but otherwise I believe it is valid under this proposal.
>>>>
>>>>> // Hey, I’ll be nice and keep it fileprivate, but I could make it public if I wanted to.
>>>>> extension Foo {
>>>>> fileprivate var foosExposedPrivates: Int {
>>>>> // Yep, I’m inside Foo so I can see it’s submoduleprivate stuff
>>>>> get { return protectedState }
>>>>> set { protectedState = newValue }
>>>>> }
>>>>> }
>>>>> }
>>>>>
>>>>>>
>>>>>> --
>>>>>> Brent Royal-Gordon
>>>>>> Architechies
>>>>>>
>>>>>> _______________________________________________
>>>>>> 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/20170221/293da7c6/attachment.html>
More information about the swift-evolution
mailing list