+1 overall. prefer this approach over the "scope based" approach in the other proposal
On Wed, Feb 22, 2017 at 10:10 AM, Matthew Johnson via swift-evolution < [email protected]> wrote: > > On Feb 21, 2017, at 11:54 PM, Robert Widmann <[email protected]> > wrote: > > > On Feb 22, 2017, at 12:41 AM, Matthew Johnson <[email protected]> > wrote: > > > > Sent from my iPad > > On Feb 21, 2017, at 11:09 PM, Robert Widmann <[email protected]> > wrote: > > > On Feb 21, 2017, at 11:59 PM, Matthew Johnson <[email protected]> > wrote: > > > On Feb 21, 2017, at 10:41 PM, Robert Widmann <[email protected]> > 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`). > > > A module is a named region that introduces a lexical scope into which > declarations may be nested. The name of the module can be used to access > these member declarations. A module, like other aggregate structures in > Swift, may be extended with new declarations over one or more translation > units (files). > > > Your API boundary lives, as it does today, at the edges of each > (sub)module declaration. APIs that are public or open in a module defines > code that is free to move across this boundary and into the open. APIs > that are internal are free to have their modules unsealed into other > internal modules to enable modular composition. APIs that are private and > fileprivate do not participate in the API boundary because they are not > eligible for any kind of export. > > If any of that is unclear, please let me know. > > > Yes, in fact parts are unclear. > > "APIs that are public or open in a module defines code that is free to > move across this boundary and into the open" > > This is unclear because you're saying submodules form an API boundary and > you're also saying we need to make APIs open or public to allow them to > move across this boundary. But then you say we can unseal it (import or > extend, right?) within the module and gain visibility to the internal > symbols. Are you trying to say that it's a soft boundary within the module > that can be permeated with an import or by extension? > > > Of course. *Soft* implies more permeability than you are actually > afforded, but if you want to think of it that way then it may help to put > it in context. > > For what it’s worth, the bulk of the discussion around this feature is > focused on author-side concerns like the behavior of internal modules > because access control makes a mess of any reasonable semantics. > > > If so, that's not the kind of boundary I think many of us are talking > about. We're talking about a hard boundary within the module, but broader > than a file. > > > How then, does one go about accessing declarations contained in these > kinds of impermeable modules? You *must* define points of exposure to be > able to use the module. What you’re describing is as though you had can > only build hierarchies of completely private types and then cherry-pick > them one-by-one into the open - which, mind you, is not a pattern > encouraged by any of the access control levels we have today and isn’t > supported by any language I’m aware of. > > > There are ways to do this without requiring cherry picking individual > types. I’m not looking for impermeable modules. I’m looking for bounded > visibility within the module in a way that is very similar to > `fileprivate`, but at a larger granularity. I’m writing up my view of > submodules so we have something more concrete to discuss. > > > > 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`. > > > Precisely. That’s the same pattern that good Swift code, arguably good > code in any language that enables hiding, uses today. > > 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. > > > Perhaps you misunderstand. Say the APIs in MyModule.Foo were all of > internal or stricter access: The re-export is a no-op. You *cannot* change > the access level of declarations, you can only do the modular thing and > wrap them in a palatable interface for export by a module you want to be > user-facing. You have to *decide* to make an API public, just as today > you have to decide to make part of an interface public. I don’t see how > this is distinct from the goals of this proposal. > > > Yes, I understand this. But submodules aren't visible outside the module > by default. It's possible for a submodule to have public and open symbols > without the top level public import anywhere in the program. > > > What I'm saying here is that someone in a distant part of the code base > could arbitrarily add it if they decided to. The system doesn't prevent > it. > > > Because, by definition, you are not in a “distant part of the codebase” > when you are extending a module. You’re introducing related functionality > under the same namespace with more related functionality. Anything else is > fundamentally anti-modular because it pollutes different concerns together > into an interlocking directorate. *Miles away* implies cognitive and > semantic distance when you’re probably physically in the same directory! > > > I understand that you consider that a non goal. I'm simply pointing out > that the system has this property. I think it's reasonable to want a > system with different properties. And I don't think it's clear yet exactly > what kind of system might garner the support necessary to be accepted as > Swift's submodule system. That's part of the reason we have these > discussions! :) > > > I so appreciate this, too. I genuinely enjoy discussions that try to poke > holes and prod out better explanations. It’s how you iterate on proposals > and just make good things happen in a community like this. > > ~Robert Widmann > > > > > 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 <[email protected]> > wrote: > > > On Feb 21, 2017, at 10:29 PM, Robert Widmann <[email protected]> > 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 <[email protected]> > wrote: > > > On Feb 21, 2017, at 10:11 PM, Matthew Johnson <[email protected]> > wrote: > > > On Feb 21, 2017, at 9:47 PM, Brent Royal-Gordon via swift-evolution < > [email protected]> wrote: > > On Feb 21, 2017, at 7:38 PM, Robert Widmann <[email protected]> > 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 > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution > > > > > > > > > > > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
