<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br><br>~Robert Widmann</div><div><br>2017/03/03 16:10、Matthew Johnson <<a href="mailto:matthew@anandabits.com">matthew@anandabits.com</a>> のメッセージ:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=utf-8"><br class=""><div><blockquote type="cite" class=""><div class="">On Mar 2, 2017, at 10:52 PM, T.J. Usiyan <<a href="mailto:griotspeak@gmail.com" class="">griotspeak@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">Submodules will, I hope, afford us the ability to share meaningfully arranged API. In an ideal scenario, I could have a module that has all of the smaller pieces of 'utilities and conveniences' that one builds up broken into submodules. Importing one of the submodules from its enclosing module shouldn't bring anything extra along. I don't think that we need to add nearly as many new concepts as `scope-based submodules` introduces. "ABI Boundaries", "Name Boundaries", "Scope Boundaries”? </div></div></div></blockquote><div><br class=""></div><div>These boundaries already exist. All the proposal does is give a name to them.</div></div></div></blockquote><div><br></div><div>Some of these boundaries (at least the first) are not meant to be user-visible. Some already exist and are just specializations of lexical scope for some reason.</div><br><blockquote type="cite"><div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="">What he have is built on LLVM Modules and holds together fairly well on its own. </div><div class="">Our projects, at present, are a module. ABI doesn't have very much to do with the 'boundary' of our target. The wording around Module maps make it clear that submodules have been considered <a href="http://clang.llvm.org/docs/Modules.html#module-maps" class="">Module Maps</a> </div><div class=""><br class=""></div><div class="">Export statements are not a useful addition. Access modifiers capture this well enough via open|public etc. When paired with robust import syntax, we would have everything that we need. </div></div></div></blockquote><div><br class=""></div><div>Can you elaborate on what you mean by “robust import syntax”? The top-level export statement has similar semantics to the `public import` in Robert and Jaden’s proposal. They even used the word “export” in describing the semantics of `public import`.</div><div><br class=""></div><div>It just uses the name `export` rather than `import` to avoid overloading the semantics of `import` and introduces additional features to avoid coupling the internal structure of a module to the view exposed to users of the module.</div><br class=""></div></div></blockquote><div><br></div><div>What about this constitutes an overload? Importing a (sub)module and exporting a (sub)module may sound disjoint because in common parlance they are opposites. As it relates to programming languages, an export is an iteration upon an import, a step up. Where an import opens a submodule's contents to the importer, an export opens a submodule's contents to an importer once removed. As such, the term "re-export" is sometimes used to make this clear. We represent such relationships with qualifiers, not new declarations.</div><br><blockquote type="cite"><div><div><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">The changes to scope and access modifiers in `scope-based submodules` are dramatic and don't seem to pay for themselves at all.</div></div></div></blockquote><div><br class=""></div><div>This aspect makes the proposal more powerful but is not essential to scope-based submodules. It has been broken out into an independent proposal which so far has received very positive feedback.</div></div></div></blockquote><div><br></div><blockquote type="cite"><div><div><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""> </div><div class=""><br class=""></div>"Top of the file" declaration to declare a submodule is not at all desirable to me. I would rather that we use the (not-entirely-pleasant-to-me) "curly brace without an indent" used for switches+cases. </div></div></blockquote><div><br class=""></div><div>If it’s not entirely pleasant why do you prefer that style?</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">LLVM modules handle circularity, I think. <br class=""></div></div></div></blockquote><div><br class=""></div><div>Do you believe circularity is important? What use cases do you have for that?</div></div></div></blockquote><div><br></div><div>What reasons do you have for disallowing it? If two (sub)modules depend on each other's contents and cannot be cleanly nested into each other, their dependency is mutual. We do not have a preprocessor - our modules are semantic rather than syntactic - so there isn't a risk of strange behavior like there is in older languages.</div><br><blockquote type="cite"><div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">The ability to import a single type or a list of specific types is of great value, in my opinion, especially when paired with renaming (we don't have it but one can dream, no?) Qualified imports are obviously the tact that I would like to make this possible. Allow the consumer of the API to get as specific as they need to when importing. I consider it an unfortunate concession that `import This.That.TheOther` imports as much as it does but it is, basically, the only major issue that I have with this proposal and it can't be helped without breaking compatibility. </div></div></div></blockquote><div><br class=""></div><div>Selective import is an additive feature that is orthogonal to submodules. I agree that it would be very nice to have, but it is a separate issue IMO.</div></div></div></blockquote><div><br></div><div>No it is not. I agree it is a separate issue, but you cannot acknowledge that the current behavior is strange and brush it off.</div><br><blockquote type="cite"><div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">Overall, it is my opinion that we should solve the submodule and import problems with changes like those proposed here. Modify very little of the current syntax and semantics. What we have is fairly close and can actually be coherent even with the additional burden of exposing submodules.</div></div></div></blockquote><div><br class=""></div><div>It sounds like you don’t view encapsulation as an important feature of submodules. Is that correct? If so, why not? Do you believe we need encapsulation boundaries larger than a file but smaller than a module?</div></div></div></blockquote><div><br></div>I cannot speak for TJ, but having read his response nowhere in it did he express a desire for anti-modularity. My own thinking here is we do not need more classification, more levels, more subdivisions to solve this problem. In fact, we currently have too many as it is, but that's yet another discussion.<div><br><blockquote type="cite"><div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""> </div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><div class="gmail_extra"><br class=""><div class="gmail_quote">On Thu, Mar 2, 2017 at 11:01 PM, Matthew Johnson <span dir="ltr" class=""><<a href="mailto:matthew@anandabits.com" target="_blank" class="">matthew@anandabits.com</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="auto" class=""><div class=""><br class=""><br class="">Sent from my iPad</div><span class=""><div class=""><br class="">On Mar 2, 2017, at 9:06 PM, T.J. Usiyan <<a href="mailto:griotspeak@gmail.com" target="_blank" class="">griotspeak@gmail.com</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class="">+1 overall. prefer this approach over the "scope based" approach in the other proposal</div></div></blockquote><div class=""><br class=""></div></span>Can you elaborate? What problems are you hoping submodules will address?<div class=""><div class="gmail-m_-6959400462724237788h5"><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="gmail_extra"><br class=""><div class="gmail_quote">On Wed, Feb 22, 2017 at 10:10 AM, Matthew Johnson via swift-evolution <span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><br class=""><div class=""><span class=""><blockquote type="cite" class=""><div class="">On Feb 21, 2017, at 11:54 PM, Robert Widmann <<a href="mailto:devteam.codafi@gmail.com" target="_blank" class="">devteam.codafi@gmail.com</a>> wrote:</div><br class="gmail-m_-6959400462724237788m_7795826770068227378m_1946814608577124963Apple-interchange-newline"><div class=""><div style="word-wrap:break-word" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Feb 22, 2017, at 12:41 AM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" target="_blank" class="">matthew@anandabits.com</a>> wrote:</div><br class="gmail-m_-6959400462724237788m_7795826770068227378m_1946814608577124963Apple-interchange-newline"><div class=""><div dir="auto" class=""><div class=""><br class=""><br class="">Sent from my iPad</div><div class=""><br class="">On Feb 21, 2017, at 11:09 PM, Robert Widmann <<a href="mailto:devteam.codafi@gmail.com" target="_blank" class="">devteam.codafi@gmail.com</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Feb 21, 2017, at 11:59 PM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" target="_blank" class="">matthew@anandabits.com</a>> wrote:</div><br class="gmail-m_-6959400462724237788m_7795826770068227378m_1946814608577124963Apple-interchange-newline"><div class=""><div style="word-wrap:break-word" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Feb 21, 2017, at 10:41 PM, Robert Widmann <<a href="mailto:devteam.codafi@gmail.com" target="_blank" class="">devteam.codafi@gmail.com</a>> wrote:</div><br class="gmail-m_-6959400462724237788m_7795826770068227378m_1946814608577124963Apple-interchange-newline"><div class=""><div class="">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.<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">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`). </div><div class=""><br class=""></div></div></div></div></blockquote><div class=""><br class=""></div></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px" class=""><div class=""><div class=""><span style="color:rgb(51,51,51);font-family:-apple-system,blinkmacsystemfont,'segoe ui',helvetica,arial,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;background-color:rgb(255,255,255)" class="">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).</span></div><div class=""><span style="color:rgb(51,51,51);font-family:-apple-system,blinkmacsystemfont,'segoe ui',helvetica,arial,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;background-color:rgb(255,255,255)" class=""><br class=""></span></div><div class=""><span style="color:rgb(51,51,51);font-family:-apple-system,blinkmacsystemfont,'segoe ui',helvetica,arial,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;background-color:rgb(255,255,255)" class=""><br class=""></span></div></div></blockquote><div class="">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. </div><div class=""><br class=""></div><div class="">If any of that is unclear, please let me know. </div></div></blockquote><div class=""><br class=""></div><div class="">Yes, in fact parts are unclear.</div><div class=""><br class=""></div><div class="">"<span style="background-color:rgba(255,255,255,0)" class="">APIs that are public or open in a module defines code that is free to move across this boundary and into the open"</span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class=""><br class=""></span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">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?</span></div></div></div></blockquote><div class=""><br class=""></div><div class="">Of course. <i class="">Soft</i> 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. </div><div class=""><br class=""></div><div class="">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. </div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="auto" class=""><div class=""><span style="background-color:rgba(255,255,255,0)" class=""><br class=""></span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">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.</span></div></div></div></blockquote><div class=""><br class=""></div><div class="">How then, does one go about accessing declarations contained in these kinds of impermeable modules? You <i class="">must</i> 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.</div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">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.</div><div class=""><div class="gmail-m_-6959400462724237788m_7795826770068227378h5"><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap:break-word" class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div dir="auto" class=""><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap:break-word" class=""><div class=""><div class=""> 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`. </div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Precisely. That’s the same pattern that good Swift code, arguably good code in any language that enables hiding, uses today.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap:break-word" class=""><div class=""><div class="">They can also trivially add a `public import MyModule.Foo` anywhere at the top level of their file because <i class="">every</i> file is forced to include top level scope.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Perhaps you misunderstand. Say the APIs in MyModule.Foo were all of internal or stricter access: The re-export is a no-op. You <i class="">cannot</i> 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 <i class="">decide</i> 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.</div></div></div></blockquote><div class=""><br class=""></div><div class="">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. </div></div></div></blockquote><br class=""><blockquote type="cite" class=""><div class=""><div dir="auto" class=""><div class="">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. </div><div class=""><br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">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. <i class="">Miles away</i> implies cognitive and semantic distance when you’re probably physically in the same directory!</div></div></div></div></blockquote><blockquote type="cite" class=""><div class=""><div style="word-wrap:break-word" class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div dir="auto" class=""><div class="">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! :)</div></div></div></blockquote><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">~Robert Widmann</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="auto" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap:break-word" class=""><div class=""><div class=""><br class=""></div><div class="">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. </div><div class=""><br class=""></div><div class="">There are quite a few of us who want the ability to form solid API boundaries <i class="">inside</i> 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.</div><div class=""><br class=""></div><div class="">I can’t speak for anyone else, but here are a few reasons why it’s important to me:</div><div class=""><br class=""></div><div class="">* Solid API boundaries are essential to good design. </div><div class="">* 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.</div><div class="">* 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.</div><div class="">* Swift currently only has whole module optimization, not whole program optimization. There is a performance penalty to using full-fledged modules.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><br class="">~Robert Widmann<br class=""><br class=""><blockquote type="cite" class="">On Feb 21, 2017, at 11:38 PM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" target="_blank" class="">matthew@anandabits.com</a>> wrote:<br class=""><br class=""><br class=""><blockquote type="cite" class="">On Feb 21, 2017, at 10:29 PM, Robert Widmann <<a href="mailto:devteam.codafi@gmail.com" target="_blank" class="">devteam.codafi@gmail.com</a>> wrote:<br class=""><br class="">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.<br class=""></blockquote><br class="">By API boundary you mean the top-level module, right?<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">On Feb 21, 2017, at 11:13 PM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" target="_blank" class="">matthew@anandabits.com</a>> wrote:<br class=""><br class=""><br class=""><blockquote type="cite" class="">On Feb 21, 2017, at 10:11 PM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" target="_blank" class="">matthew@anandabits.com</a>> wrote:<br class=""><br class=""><br class=""><blockquote type="cite" class="">On Feb 21, 2017, at 9:47 PM, Brent Royal-Gordon via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class=""><blockquote type="cite" class="">On Feb 21, 2017, at 7:38 PM, Robert Widmann <<a href="mailto:devteam.codafi@gmail.com" target="_blank" class="">devteam.codafi@gmail.com</a>> wrote:<br class=""><br class="">Correct. Because, in dividing the submodule across an extension, you have placed what should be a private API into a differently-scoped location.<br class=""></blockquote><br class="">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.<br class=""></blockquote><br class="">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).<br class=""><br class="">// File 1<br class="">module Foo {<br class="">// internal, visible to the whole module<br class="">class Bar { submoduleprivate var protectedState: Int = 0 }<br class="">}<br class=""><br class="">// File 2 - Has nothing to do with Foo at all<br class="">import MyModule.Foo<br class=""><br class="">module NotFoo {<br class="">// Hey, I need to see Bar.protectedState!!!<br class="">func totallyNotFoo() {<br class=""> var bar = Bar()<br class=""> bar.foosExposedPrivates = 42<br class="">}<br class="">}<br class=""><br class="">// ok, I’ll just add an extension to Foo so I can see submoduleprivate and wrap what I need<br class="">module Foo {<br class=""></blockquote><br class="">Oops, this should have been `extension Foo`, but otherwise I believe it is valid under this proposal.<br class=""><br class=""><blockquote type="cite" class="">// Hey, I’ll be nice and keep it fileprivate, but I could make it public if I wanted to.<br class="">extension Foo {<br class=""> fileprivate var foosExposedPrivates: Int {<br class=""> // Yep, I’m inside Foo so I can see it’s submoduleprivate stuff<br class=""> get { return protectedState }<br class=""> set { protectedState = newValue }<br class=""> }<br class="">}<br class="">}<br class=""><br class=""><blockquote type="cite" class=""><br class="">-- <br class="">Brent Royal-Gordon<br class="">Architechies<br class=""><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/mailma<wbr class="">n/listinfo/swift-evolution</a><br class=""></blockquote><br class=""></blockquote><br class=""></blockquote><br class=""></blockquote><br class=""></blockquote><br class=""></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></div></blockquote></div></div></blockquote></div><br class=""></div></div></blockquote></div></div></div><br class=""></div><br class="">______________________________<wbr class="">_________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailma<wbr class="">n/listinfo/swift-evolution</a><br class="">
<br class=""></blockquote></div><br class=""></div>
</div></blockquote></div></div></div></div></blockquote></div><br class=""></div></div></div>
</div></blockquote></div><br class=""></div></blockquote></div></body></html>