> On Feb 26, 2017, at 10:47 PM, Jonathan Hull <[email protected]> wrote: > >> >> On Feb 25, 2017, at 2:41 PM, Matthew Johnson <[email protected] >> <mailto:[email protected]>> wrote: >> >>> >>> On Feb 25, 2017, at 4:01 PM, Jonathan Hull <[email protected] >>> <mailto:[email protected]>> wrote: >>> >>>> >>>> On Feb 25, 2017, at 1:19 PM, Matthew Johnson <[email protected] >>>> <mailto:[email protected]>> wrote: >>>>> On Feb 25, 2017, at 2:54 PM, Jonathan Hull via swift-evolution >>>>> <[email protected] <mailto:[email protected]>> wrote: >>>>> +1000 >>>>> >>>>> This is the best of the proposals I have seen. I think it works by >>>>> itself as a complete proposal, but since we are talking "comprehensive >>>>> rethink", there is one use case which most of the proposals seem to miss. >>>>> >>>>> >>>>> That is, what if I want to make a class which is both Public and >>>>> Subclassable, but I want to keep some of the implementation details >>>>> private to the class, while still allowing subclasses and extensions >>>>> (across the module boundary) to have access to those details. A concrete >>>>> example of this is UIGestureRecognizer, which is intended to be >>>>> subclassed outside of its framework, but hides potentially catastrophic >>>>> things (like being able to set the state) from callers. This isn’t >>>>> currently possible in Swift AFAICT without importing from ObjC. >>>>> >>>>> My solution to this has been to allow something to be marked ‘public >>>>> hidden’ or ‘hidden', which means that it is public/internal, but has it’s >>>>> visibility limited only to files which opt-in to seeing it with ‘import >>>>> hidden filename’ (instead of just ‘import filename’). I think this is >>>>> the simplest way to provide this feature, which is sometimes very >>>>> necessary. It also captures authorial intent very nicely. >>>> >>>> My submodule proposal is able to support this use case. You would just >>>> put the symbols intended for subclasses in a separate submodule. These >>>> submodules could be exposed to users with any name you desire, regardless >>>> of the internal structure of your module. You could even arrange for >>>> users to get all of the non-subclass-only symbols automatically when they >>>> import your module but require explicit import of each individual >>>> subclass-only submodule in places where it is needed. >>> >>> I agree that this could also be solved with nested submodules >> >> A minor note, but you would not need to nest them. You could do it either >> way. > > I can’t think of how to do this, but I trust you that it can. > > >>> , but the current proposals all seem to add a lot of complexity. This >>> complexity does give you much finer grain control over visibility, but what >>> I like about Nevin’s proposal is that it is ‘just enough’ control with >>> minimal complexity. >> >> Determining what “just enough” is is obviously a very subjective thing. :) >> Everyone seems to have their own opinion about this (more than usual) which >> is going to make it one of the more complicated discussions we’ll have on >> the list. >> >> I worked very hard on my proposal to try to design a system that stays out >> of your way until you need the tools it offers. That way nobody is faced >> with complexity unless they are deriving direct benefit from it, but when >> they need powerful tools those tools are available. This is the idea of >> progressive disclosure (as I understand it). > > True. I would personally define “just enough” as easy for the 80% and > possible for the 98%. > > I don’t think your proposal is bad at all. I just like the simplicity of > Nevin’s a little more (especially with the confusion around ‘open’). In fact, > I would like to see you combine them a bit (see below). > > >>> What I like about ‘hidden’ vs export of nested submodules is that you can >>> freely intermix those declarations in your code (like you can with private >>> now). >> >> Yeah, this is an advantage. It’s not a bad idea, but it’s not a replacement >> for submodules either. They are complementary. > > Agreed. > > What I would really like to see is Nevin’s proposal with a simplified version > of yours providing the submodules, and something like ‘hidden’ replacing the > idea of ‘export’.
Are you saying you want to see all submodules exposed externally automatically? Or are you only talking about non-top-level export? > > In more detail, I really like just having ‘private’, ‘internal’, and ‘public’ > where private means private to the submodule. It is very simple and > understandable. I think having a single level of submodule using your > ‘submodule’ syntax is the simplest way to provide those. I think there is going to be *a lot* of resistance to the idea of removing file-level private. Most people want to keep that, but just revert than name to `private` like we had in Swift 2. > > I think I would be ok with nested submodules as well, again using your > syntax, as long as we have ‘private’ mean private within the current > submodule (and children). If we find we really do need parametrized private > (or equivalent) to provide visibility to a specific parent scope, that is > something that can be an additive (non-breaking) change later. I think we > will be able do pretty much everything we need to without it though. I could be wrong, but I’d be willing to bet that in a submodule world you would have a very vocal and large number of people complaining if we suggest not including any of: module-wide visibility, submodule-wide visibility and file-wide visibility. There are certainly people who think that one or another of these is not worth supporting but I don’t see anything near a consensus around avoiding any one of these. Each will have a very vocal group of proponents that I believe (again I could be wrong) would be a majority with respect to that particular scope. I can understand why somebody might prefer a style that avoids relying one of these scopes (people have their idiosyncrasies after all). What I have a hard time understanding is why somebody would propose that *nobody* be able to scope a symbol to one of these very physical and prominent scopes. > > > >> One thing `hidden` doesn’t do is allow you to say *why* the symbols are >> hidden and make that clear when they are imported. I can imagine allowing >> it to take a parameter that is a user-defined identifier stating *why* the >> symbols are hidden. For example, I might have `hidden(subclass)` and >> `hidden(extension)`. Making it a user-defined identifier would encourage >> names that mean something, require users to have read the documentation >> telling them what the identifier is, and make it clear to readers of the >> code why hidden symbols are imported (if the identifier used does not match >> any available symbols it would result in a compiler error). >> >> A user-defined identifier would also be better than a small set of >> language-defined arguments because users would expect language-defined >> identifiers like “subclass” or “extension” to be *enforced* by the language. >> There has been strong pushback against doing that for several reasons. A >> parameterized `hidden` is a general feature that could express what is >> desired very well while not over-promising and under-delivering `protected` >> or `typeprivate` are extremely permeable restrictions and therefore don’t >> offer any real guarantees that `hidden` or a factored out submodule wouldn’t >> offer. It’s better to have a more general feature that does exactly what it >> says and leads users to believe it does. > > I disagree. The whole point of ‘hidden’ is to protect the *callers* of a > type from accidentally invoking its deliberate extension points. It > basically means “don’t touch these unless you understand them”, and having to > ‘import hidden’ is explicitly taking responsibility for this. I don’t think > making extenders type a secret code would actually help anything, and would > just annoy/complicate. There is only so much you can do to protect people > from themselves. > > Right now, anything that would be marked ‘public hidden’ has to be marked > ‘public’, so I think it is a thorough improvement over the status quo. That’s a reasonable perspective. This feature seems like it could certainly be useful in some cases but it’s applicable in relatively narrow cases and is orthogonal to the things I am interested in focusing on right now so I don’t plan to propose it. I’m happy to wait and see if somebody else decides to run with it. > >> >>> There is also the question of how to separate a single type into multiple >>> submodules, when we can’t declare storage in an extension. >> >> We have discussed allowing storage to be declared in an extension in the >> past on the list. There is reasonable support for adding this eventually >> and we have ideas about how to do it (the complexity is primarily around >> insuring proper initialization of storage declared in extensions). >> Introducing a submodules feature could well drive demand for it by >> demonstrating concrete use cases where it becomes more necessary. >> >> Even without that feature it is possible to separate a type into separate >> submodules using the features in my proposal. The details of how you do >> that would depend on concrete use cases. > > True, and I do want this feature… but I don’t want to rely on it being there > when it is not yet on the roadmap. > > Thanks, > Jon
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
