> 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

Reply via email to