> On Mar 6, 2017, at 10:22 AM, Michel Fortin <[email protected]> wrote:
> 
> I believe `submodule` in my proposal introduces a segmented-scope-like thing, 
> akin to how the various files included in a module are combined as one 
> collection of declarations. And you have the ability to import things from 
> that scope with `import submodule`, like with modules. I think the name 
> submodule fits as some sort of "lesser module", but if someone has a better 
> name for this I'll listen.
> 

My beef is not with that, my beef is with the idea that `public` should leak 
APIs across module boundaries by default and that a module is merely a way to 
section off internal declarations.  Matthew has given these a name in his 
scoped access proposal, and Swift today gives the kind of scope you’re trying 
to define a name - it’s called fileprivate.

> We could add a submodule-private access level, but I'm not sure it is worth 
> its weight. There's plenty of possibilities, but I know I wouldn't be too 
> happy with more access levels than what we have now. For each access level 
> you add the more fine-grained they become and the more difficult it is to 
> decide which one is the right one. Hence why I'm keeping the idea of adding 
> access levels as a separate concern worth of its own debate. This proposal is 
> solely focused on providing intra-module boundaries, and I think those 
> boundaries can work without introducing a new access level.
> 
>> On 6 mars 2017, at 2:39, Robert Widmann <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>> If this were a problem that could be fixed by tooling, you'd be submitting 
>> this proposal against the package manager.
>> 
>> It's important to note I'm approaching this problem from the principles that 
>> underpin modular programming practices in other languages, it is not merely 
>> "philosophical".  A proposal that claims to support submodules should come 
>> with some consistent support for modularity or rebrand to more honestly 
>> reflect its contents.  As it stands, this proposal effectively introduces 
>> another level of access (while paradoxically claiming to avoid access 
>> control discussions), and suggests more access control to support its 
>> contents later.  Maybe discussion should start there instead of with 
>> "submodules".
>> 
>> ~Robert Widmann
>> 
>> 2017/03/06 0:39、Michel Fortin <[email protected] 
>> <mailto:[email protected]>> のメッセージ:
>> 
>>> 
>>>> On 5 mars 2017, at 22:28, Robert Widmann <[email protected] 
>>>> <mailto:[email protected]>> wrote:
>>>> 
>>>> This proposal strikes me not as a submodules proposal, but as a sneaky way 
>>>> to add 'friend' to Swift.  It is conceptually simpler because it doesn't 
>>>> address modularity at all!
>>>> 
>>>> ~Robert Widmann
>>>> 
>>>> 2017/03/05 17:16、Michel Fortin via swift-evolution 
>>>> <[email protected] <mailto:[email protected]>> のメッセージ:
>>>> 
>>>>> Sorry for introducing yet another submodule proposal out of the blue.
>>>>> 
>>>>> I'm a bit surprised at how far-reaching the various submodule proposals 
>>>>> floated on this list have been. Directories, access controls, @exported 
>>>>> imports... For comparison's sake here's one that is *really* simple and 
>>>>> short I wrote today. Best of all: it requires no new access modifier. 
>>>>> 
>>>>> I also expect everyone to scream at it because it does not include all 
>>>>> the desirable features of a submodule system. At the very least I'll have 
>>>>> redefined the meaning of lightweight in that discussion. Good reading.
>>>>> 
>>>>> Also available here: 
>>>>> https://gist.github.com/michelf/779b1bc26a778051b6231b5639665e18 
>>>>> <https://gist.github.com/michelf/779b1bc26a778051b6231b5639665e18>
>>>>> 
>>>>> 
>>>>> ## Motivation
>>>>> 
>>>>> The goal of this proposal is to provide lightweight intra-module 
>>>>> boundaries so you can avoid exposing every `internal` declaration within 
>>>>> a big module to all other files in the module.
>>>> 
>>>> I don't think this was a stated goal of anybody because that’s not the 
>>>> primary issue submodules are trying to solve.  Projects with a large 
>>>> amount of internal declarations may be clamoring to be put into multiple 
>>>> (sub)modules, but because the style most have converged on doesn’t usually 
>>>> involve a large amount of free functions, your internal declarations are 
>>>> usually types and as such have members that are already encapsulated.
>>> 
>>> Well maybe that's just a problem specific to me, but that's the goal I'd 
>>> like submodule to solve. If I have four intermingled classes, I'd like to 
>>> restrict the interminglement to those four classes. My current options for 
>>> that are a) to create a separate module, b) to put them all in the same 
>>> file with `fileprivate`, or c) tolerate that the rest of the module will 
>>> see everything all the time with `internal`. I'm choosing (c) at the 
>>> present time because (a) is too much work and (b) is more messy.
>>> 
>>> You are absolutely right in your observation that it's some sort of 
>>> "friend". But then the same observation could apply to the `internal` 
>>> members in a module or the `fileprivate` members in a file. The delimiting 
>>> boundaries are different, but the concept is the same. What I want is the 
>>> ability to better define those boundaries.
>>> 
>>>>> Not a goal: addressing the file-level access fileprivate/private or 
>>>>> scoped/protected debates. This is left to other proposals.
>>>>> 
>>>>> 
>>>>> ## Summary
>>>>> 
>>>>> This proposal adds the declarations `submodule` and `import submodule`. 
>>>>> It also limits the visibility of `internal` to files with a matching 
>>>>> `submodule` or `import submodule` declaration.
>>>>> 
>>>>> Submodules are never exposed outside of the module. They only change the 
>>>>> visibility of internal declarations, so there is no point in exposing 
>>>>> them publicly.
>>>>> 
>>>>> Submodules are not bound to directories, nor are they necessarily 
>>>>> hierarchical.
>>>>> 
>>>>> This change is purely additive and introduces no source compatibility 
>>>>> issue.
>>>> 
>>>> This particular set of changes is, but the `import submodule` change is 
>>>> source-breaking in that we already have syntax for this.
>>> 
>>> Good catch. If you have a module called "submodule" and you import it, 
>>> that'll break.
>>> 
>>>>> 
>>>>> 
>>>>> ## Details
>>>>> 
>>>>> A `submodule <name>` declaration at the beginning of a file contains an 
>>>>> identifier with the submodule name:
>>>>> 
>>>>>  submodule Foo
>>>>> 
>>>>>  internal func foo() {}
>>>>>  public func pub() {}
>>>>> 
>>>>> `internal` declarations within that file are only visible to other files 
>>>>> sharing the same submodule name. The submodule only protects `internal` 
>>>>> declarations: `public` declarations in the file are visible everywhere 
>>>>> (in other submodules and in other modules).
>>>>> 
>>>> 
>>>> This definition of public is anti-modular.  It seems as though this style 
>>>> of submodule will encourage people to split their definitions across 
>>>> multiple files (good) then provide a pile of submodule-membership 
>>>> definitions to intertwine them with each other as they need access to each 
>>>> other’s symbols (bad). A module is a self-contained entity by definition.  
>>>> Dependencies should generally be on further child (sub)modules - 
>>>> vertically, not horizontally.
>>> 
>>> I'll say that this definition of `public` is quite handy as long as the 
>>> submodules are implementing public-facing functionality. I agree it is less 
>>> useful when the submodule is the backend of some other component in the 
>>> module. You are thus right in that it naturally organizes things 
>>> horizontally.
>>> 
>>> So if you want to use submodules to organize self-contained dependencies, 
>>> my approach does not work very well. In particular, there is no containment 
>>> of anything `internal` when you `import submodule Foo`. That would be 
>>> improved if we had submodule-private as discussed in Future Directions... 
>>> with the caveat that it's still easy to access any submodule's internals by 
>>> declaring any file to be part of the submodule. And also you want a strict 
>>> hierarchy, which this proposal completely eschew.
>>> 
>>> We obviously have a different philosophy on how strict and hierarchic the 
>>> submodules should be. I say the strictness should stay at the module 
>>> boundaries. If you want enforced self-contained modules, change those 
>>> submodules into full modules. If you want to ship the whole thing as a 
>>> single library, then we need to adapt the tooling so you can merge 
>>> privately those modules inside of the main library. (Ideally this would be 
>>> done with a single compiler invocation, allowing full cross-module 
>>> optimization.) This is a tooling and packaging problem that does not need 
>>> to leak into a plethora of new language concepts. At least, this is how I 
>>> see it.
>>> 
>>> 
>>>>> A file can be part of more than one submodule:
>>>>> 
>>>>>  submodule Foo
>>>>>  submodule Bar
>>>>> 
>>>>>  internal func achoo() {
>>>>>      foo() // available in Foo (from other file)
>>>>>  }
>>>>> 
>>>>> This makes the internal `achoo` function visible within both the `Foo` 
>>>>> and `Bar` submodules. Also note that it makes internal members of both 
>>>>> submodules `Foo` and `Bar` visible within the file.
>>>>> 
>>>>> A file can access internal declarations of a submodule without having to 
>>>>> expose its own internal functions to the submodule with `import 
>>>>> submodule`:
>>>>> 
>>>>>  submodule Test
>>>>>  import submodule Foo
>>>>> 
>>>>>  internal func test() {
>>>>>      foo() // internal, imported from Foo
>>>>>      achoo() // internal, imported from Foo
>>>>>      pub() // public, so always visible
>>>>>  }
>>>>> 
>>>>> Finally, when a file has no submodule declaration, its internal 
>>>>> declarations are visible everywhere in the module and all its submodules:
>>>>> 
>>>>>  --- Hello.swift ---
>>>>>  // no submodule declaration
>>>>>  internal func hello() {}
>>>>> 
>>>>>  --- World.swift ---
>>>>>  submodule World
>>>>>  internal func test() {
>>>>>      hello() // visible!
>>>>>  }
>>>>> 
>>>>> 
>>>>> ## Nitpicky Details (Conflicting Declarations)
>>>>> 
>>>>> Declaring `internal` things that share the same name in two separate 
>>>>> submodules is not a conflict:
>>>>> 
>>>>>  --- Foo1.swift ---
>>>>>  submodule Foo1
>>>>>  class Foo {} // added to Foo1
>>>>> 
>>>>>  --- Foo2.swift ---
>>>>>  submodule Foo2
>>>>>  submodule Foo3
>>>>>  class Foo {} // added to Foo2 and Foo3
>>>>> 
>>>>> (Note: It would be a conflict if one of them was `public`, because 
>>>>> `public` declarations are always visible everywhere inside (and outside 
>>>>> of) the module.)
>>>>> 
>>>>> Attempting to use both from another submodule will create ambiguity 
>>>>> errors. You can disambiguate using the submodule name as a prefix:
>>>>> 
>>>>>  --- Main.swift ---
>>>>>  import submodule Foo1
>>>>>  import submodule Foo2
>>>>>  import submodule Foo3
>>>>>  let f0 = Foo() // ambiguity error
>>>>>  let f1 = Foo1.Foo() // good
>>>>>  let f2 = Foo2.Foo() // good
>>>>>  let f3 = Foo3.Foo() // good
>>>>> 
>>>>> Best to avoid this for your own sanity however.
>>>>> 
>>>>> 
>>>>> ## Alternatives Considered
>>>>> 
>>>>> ### Conflicting Declarations
>>>>> 
>>>>> Instead of allowing conflicting symbols in different submodules, we could 
>>>>> continue to disallow conflicting `internal` declarations even when they 
>>>>> belong to different submodules. This would make the design simpler, as it 
>>>>> is closer to how `internal` currently works and prevent ambiguity errors 
>>>>> from arising when importing multiple submodules. The behavior would be a 
>>>>> little surprising however.
>>>>> 
>>>>> We could also simplify by removing the ability to use the submodule name 
>>>>> as a prefix to disambiguate. This has the advantage that if you put a 
>>>>> type inside of a submodule with the same name, no conflict can arise 
>>>>> between the name of the type and the name of the submodule. 
>>>>> Disambiguation would have to be done by renaming one of the conflicting 
>>>>> declarations. Since this ambiguity can only affect `internal` 
>>>>> declarations (submodules only group internal declarations), requiring a 
>>>>> rename will never break any public API. But forcing a rename is not a 
>>>>> very elegant solution.
>>>>> 
>>>>> ### `import` syntax
>>>>> 
>>>>> Renaming `import submodule` to `import internal`. Having "internal" in 
>>>>> the name could make it clearer that we are giving access to internal 
>>>>> declarations of the submodule. But it also make the import less relatable 
>>>>> to the `submodule` declaration in other files.
>>>>> 
>>>>> 
>>>>> ## Future Directions
>>>>> 
>>>>> ### Submodule-Private
>>>>> 
>>>>> While a submodule-private access modifier could have been added to this 
>>>>> proposal, the belief is that this proposal can live without it, and not 
>>>>> having this greatly reduce the little details to explore and thus 
>>>>> simplifies the design.
>>>>> 
>>>>> In many cases you can work around this by putting "private" stuff in a 
>>>>> separate submodule (somewhat similar to private headers in C land). For 
>>>>> instance:
>>>>> 
>>>>>  --- Stuff.swift ---
>>>>>  submodule Stuff
>>>>>  submdoule StuffImpl
>>>>> 
>>>>>  func pack() { packImpl() }
>>>>> 
>>>>>  --- StuffImpl.swift ---
>>>>>  submodule StuffImpl
>>>>> 
>>>>>  func packImpl() { ... }
>>>>> 
>>>>> This will not work for stored properties however. A future proposal could 
>>>>> suggest allowing stored properties in extensions to help with this.
>>>>> 
>>>>> And a future proposal could also add submodule-private to limit 
>>>>> visibility of some declarations to only those files that are part of a 
>>>>> specific module. 
>>>>> 
>>>>> 
>>>>> -- 
>>>>> Michel Fortin
>>>>> https://michelf.ca <https://michelf.ca/>
>>>>> 
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> [email protected] <mailto:[email protected]>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> 
>>> -- 
>>> Michel Fortin
>>> https://michelf.ca <https://michelf.ca/>
> 
> -- 
> Michel Fortin
> https://michelf.ca <https://michelf.ca/>

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

Reply via email to