> On Feb 21, 2017, at 10:41 PM, Robert Widmann <devteam.cod...@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 <matt...@anandabits.com> wrote: >> >> >>> On Feb 21, 2017, at 10:29 PM, Robert Widmann <devteam.cod...@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 <matt...@anandabits.com> >>>> wrote: >>>> >>>> >>>>> On Feb 21, 2017, at 10:11 PM, Matthew Johnson <matt...@anandabits.com> >>>>> wrote: >>>>> >>>>> >>>>>> On Feb 21, 2017, at 9:47 PM, Brent Royal-Gordon via swift-evolution >>>>>> <swift-evolution@swift.org> wrote: >>>>>> >>>>>>> On Feb 21, 2017, at 7:38 PM, Robert Widmann <devteam.cod...@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@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