I would want a keyword (key-name?) to use instead of the actual module name. Modules are defined outside of the source itself, either in the xcodeproj or Package.swift fie. It should be possible to change the module's name independently of the source it contains.
I think that it would be a little bizarre for a submodule/namespace that was used to organize internal implementation details of a module to be exposed outside the module, especially if there are no accessible members within it. Forcing this posture on developers would harm the usefulness/usability of them, in that then the developer would be forced to consider the visible namespace name even for purely internal/private code.
The idea is that namespaces act as a sort of embedded (sub)module within a module. Without an access modifier, the toolchain would not know if the code was meant to be visible outside of the enclosing module. It's essentially a type that can't be instantiated, and thus, to be usable, must have only static members.
If one were to separate out the submodule aspect, you would be correct. However, this meta-proposal is specifically to be a cross between the two.
I'm not strictly opposed to the approach, just wanting to think through the angles, is all.
The protocols comparison is apt: With protocols I often declare them at the first point of use and sometimes reach a tipping point where it makes more sense to break them out into their own file (often based on how widespread their conformances are, or whether they are first-class types themselves). So I tend to have a mix of protocols defined side-by-side with a conforming type, and some defined in their own file.
I expect this pattern would wind up being similar, but the nice thing about it is that it allows for directory-based organization or all-in-one-file organization, as you like.
+--- Submodule B // Reference A directly if unambiguous or by qualified access.
I agree with you that Submodule B should be able to reference code in its super-module A without any restriction.
The problem with qualified access here (as @Avi pointed out) is that the code within the Module shouldn't have to know the name of it's own module. This suggests either the introduction of a Module
keyword similar to Self
or some other syntax to qualify ambiguities.
I actually wouldn't mind having a rule that a submodule isn't allowed to be ambiguous with names within it's super-module. That seems perfectly reasonable since by definition the code is all owned by the same module. But I may not be seeing a really good use-case for this at the moment.
I'm a little leery of implicit-creation-by-redeclaration patterns, and the kinds of invisible errors they can create. What happens when I inevitably typo the name of the submodule in one place, and unexpectedly create a new submodule? Maybe its not an issue, or we can rely on autocomplete to help keep us safe, but it worries me. Imagine if instead of struct Foo
and extension Foo
you just used struct Foo
in multiple places for both?
That's a good point, but I think its impact depends on the tooling. Suppose there is a namespace Foo
that has no public members. When doing autocompletion and intellisense from outside Foo
, SourceKit could simply not show Foo
, since it knows there are no accessible names from outside of it.
Like so, with a supportive enough tooling, this issue can be completely mitigated.
My 2c on this:
Syntactically, we should have a definition of a namespace, like this:
namespace Foo {}
and given that it should probably have braces, it should allow things to be defined inside of it explicitly. However, I agree we don't want to have entire files nested under namespaces. Something file-based like Java's package system is one very reasonable approach on this: a definition in the file specifies the default namespace for everything within it.
Another (complementary) approach we could consider is to allow defining declarations explicitly in namespaces, e.g.:
struct Foo.MyStruct {
}
Semantically, I think it is really important to think about the role and behavior of submodules, and whether we really want something like namespaces, or something more highly developed like a submodule. We already have the ability to import submodules from ObjC modules (e.g import Foundation.NSArray) but it is not fully baked out and not developed with Swift submodules in mind.
It is important to understand that space before tackling something like this.
-Chris
Thanks for jumping in Chris. This echoes my thoughts. Personally, I would like to see submodules focus first and foremost on providing a tool that helps to manage the internal dependency structure of a large module.
I'm honestly not sure what the difference is, if namespaces are import
able. Unless you mean re-exporting modules as importable parts of a module that uses them, which is clearly something that needs to happen in any case.
Also, regardless of how submodules and namespaces turn out, referring to the current module is already a pain point when it is required (which is, thankfully, rare), so there probably needs to be a way to reference it other than by name.
This.
There is a really frustrating gap in code organization in Swift currently. We have mechanisms for organizing code at the file level, and at the module level, but module-level organization breaks down very quickly when writing applications (see above) or large modules, while file-level organization breaks down almost immediately when building large or complex functionalities. Giant multi-K lines-long files are not good organizational practice: They result in a breakdown of clear single-responsibility, muddying of inter-idependencies, and reduced readability/grokking of overall code due to vertical stacking.
In a moderately complex codebase, there are types and interfaces that are not intended for general use, but we're forced to choose between making them internal
(and thus visible, auto-completable, and conflict-able everywhere in the module), or making them file/private
and stuffing all related code into a single file. As soon as two such constellations of functionality have a relationship, one then has to face again the necessity of lumping both chunks of code into the same file, and before long, there's no clear separation of dependencies.
IMHO, a robust submodule solution can be used to solve "namespace"-y problems. A simple namespaces implementation probably won't be sufficient to solve the broader code organization problems above.
I would love submodules, but please oh please only allow public/open as modifiers ala rust submodules.
While I don't know rust and I might be misunderstanding you because of that, I did a quick read of the rust module documentation and this in particular seems to disagree with your statement about only public/open modifier access. It looks like you can have the equivalent of swift's internal
and private
with modules you just have to organize them properly to have that behavior. If there is more to it than my quick read led me to believe please share so I can make sure I understand what you mean.
That said, I really want to have mechanisms that allow internal
or private
submodules or namespaces to properly organize library code. I see no value in preventing swift users from fully organizing code just because of the access modifiers.
Submodules and namespaces aside, the latter syntax would already make sense for nested types today. That way we won't be force to include the nested type into the parent type body nor into an extension of the parent type. The extensions already require that syntax today, but the declarations do not allow it yet. Do you think such a small enhancement is worth pushing forward in a different thread?
I would be up for moving that part of the discussion to another thread. It has felt awkward to me that extensions have behaved this way for forever while you can't declare things this way.
internal is implied and something like private is reached by nesting. The only reason to introduce submodules IMO is to address the access modifier story. If we are not able to address that then probably not worth it. Simplification is hard.
I'm fairly certain (based on previous commentary by the core team) that further changes to access control is firmly off the table. Submodules will have to be a purely additive language feature, and will have to participate in the access control story as it exists today.
Having said that, IMHO, it is fundamental to the concept that a submodules feature must allow more granular access control between internal (module) and fileprivate (file). If it doesn't do that, it's useless complexity.
Agreed.
Strongly disagree. This would be the “useless complexity”
If we are introducing a new way to scope code then we can cut the complexity by only allowing access control to be done via submodules public(open)/internal. If somebody is opting for submodules then this would be purely additive and 100% non breaking. If we can’t agree about that then submodules are dead before arrival.
I don't think we actually disagree in intent. I strongly believe that SE-0025 was a huge mistake, but I'm just reiterating what has been said on this forum multiple times. I'll stop and let the core team weigh in if they choose.
But—again, IMHO—saying that if we can't rewrite the access control story in Swift then we can't have a submodules feature that might make that story easier to live with seems counter-productive to me.
The whole premise of submodules is access control. I just can not think of another reason for submodules but access control.
I must be missing something. Honestly, what am I missing?
Scope private inside submodules would be a disaster, sometimes private meaning public othertines internal. Fileprivate in submodules would have access across modules without explicit public access to the submodule.
I am a BIG fan of the introduction of the namespace
keyword into the Swift programming language!