[Proposal] Nested extensions


(Tino) #1

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#introduction>Introduction

By removing the restriction that extensions can only be used as top-level declarations, this important feature of Swift could become more powerful and solve issues some users have with access control.

Swift-evolution thread: Enhancing access levels without breaking changes <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170403/035319.html>
<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#motivation>Motivation

Currently, access control is a very hot topic for Swift, and all of the options discussed so far had strong resistance from different parts of the community.

This concept tries to avoid all objections that were raised against the various modells (of course, it triggers fresh ones at the same time ;-), and because it is purely additive, it removes the pressure to address the current issues in Swift 4. Although it wasn't a motivation, the proposal also offers an answer to the question if (and how) properties should be allowed in extensions.

SE-0169 would render major parts of this idea useless, so I think it's qualified to be discussed in this stage.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#proposed-solution>Proposed solution

Simply remove the restriction that extensions can only be declared on top-level of a file.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#detailed-design>Detailed design

There isn't much to add here: Extensions should be allowed in type declarations and other extensions (I'm skipping methods in this draft - I see neither big problems associated with extensions declared inside methods, nor convincing use cases for them).

The rules should be the same as for nested types, so marking a member of an extension private would restrict its visiblity to the scope of this extension.

The goals of SE-0169 could be achieved in this model by simply putting an extension inside a type declaration, while keeping private members protected.

Nested extensions should also be allowed to contain stored properties of the enclosing class, thus enabling better visibility management for those as well:

Stored properties in extensions have been requested before, but this approach enables them quite naturally, as the rule that you can only declare stored properties inside the declaration of a type is respected.

It would also be possible to levearage the "default access level" feature of extensions to group properties that should have the same visibility.

Because there is no natural limit of nesting extensions, this feature enables developers to design more sophisticated systems of access rights, without increasing Swifts complexity for users that are happy with "puplic-internal-private" and don't see the need for additional keywords or other changes in the language.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#future-enhancements>Future enhancements

For extensions of an enclosing type, that type could be easily inferred, so some repetition could be eliminated easily.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#source-compatibility>Source compatibility

Purely additive

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#effect-on-abi-stability>Effect on ABI stability

There are some pitfalls associated with ABI, but I don't think its stability would be affected.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#effect-on-api-resilience>Effect on API resilience

Nono known

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#alternatives-considered>Alternatives considered

SE-0169, SE-0159, renaming "fileprivate" and/or "private"

All of those possibilities have their own strengths and weaknesses, and there is a huge dissent which of those are important: No matter which would be choosen, at least one group of Swift users is punished.


(Jon Hull) #2

+1

···

On Apr 14, 2017, at 2:40 AM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#introduction>Introduction

By removing the restriction that extensions can only be used as top-level declarations, this important feature of Swift could become more powerful and solve issues some users have with access control.

Swift-evolution thread: Enhancing access levels without breaking changes <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170403/035319.html>
<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#motivation>Motivation

Currently, access control is a very hot topic for Swift, and all of the options discussed so far had strong resistance from different parts of the community.

This concept tries to avoid all objections that were raised against the various modells (of course, it triggers fresh ones at the same time ;-), and because it is purely additive, it removes the pressure to address the current issues in Swift 4. Although it wasn't a motivation, the proposal also offers an answer to the question if (and how) properties should be allowed in extensions.

SE-0169 would render major parts of this idea useless, so I think it's qualified to be discussed in this stage.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#proposed-solution>Proposed solution

Simply remove the restriction that extensions can only be declared on top-level of a file.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#detailed-design>Detailed design

There isn't much to add here: Extensions should be allowed in type declarations and other extensions (I'm skipping methods in this draft - I see neither big problems associated with extensions declared inside methods, nor convincing use cases for them).

The rules should be the same as for nested types, so marking a member of an extension private would restrict its visiblity to the scope of this extension.

The goals of SE-0169 could be achieved in this model by simply putting an extension inside a type declaration, while keeping private members protected.

Nested extensions should also be allowed to contain stored properties of the enclosing class, thus enabling better visibility management for those as well:

Stored properties in extensions have been requested before, but this approach enables them quite naturally, as the rule that you can only declare stored properties inside the declaration of a type is respected.

It would also be possible to levearage the "default access level" feature of extensions to group properties that should have the same visibility.

Because there is no natural limit of nesting extensions, this feature enables developers to design more sophisticated systems of access rights, without increasing Swifts complexity for users that are happy with "puplic-internal-private" and don't see the need for additional keywords or other changes in the language.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#future-enhancements>Future enhancements

For extensions of an enclosing type, that type could be easily inferred, so some repetition could be eliminated easily.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#source-compatibility>Source compatibility

Purely additive

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#effect-on-abi-stability>Effect on ABI stability

There are some pitfalls associated with ABI, but I don't think its stability would be affected.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#effect-on-api-resilience>Effect on API resilience

Nono known

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#alternatives-considered>Alternatives considered

SE-0169, SE-0159, renaming "fileprivate" and/or "private"

All of those possibilities have their own strengths and weaknesses, and there is a huge dissent which of those are important: No matter which would be choosen, at least one group of Swift users is punished.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Jaden Geller) #3

This proposal definitely needs to be more detailed, but I think I would be +1 on the idea.

···

---

Use cases:

1) Extending nested types

// currently possible:
extension Foo.Bar {
  // must qualify some names with Foo
}

// could be possible:
extension Foo {
  extension Bar {
    // everything in Foo is in scope
  }
}

2) Anonymous extensions

// stretch feature:
func foo() {
  extension Array {
    // helpers used inside function
  }
}

---

Cheers,
Jaden Geller

On Apr 14, 2017, at 2:40 AM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#introduction>Introduction

By removing the restriction that extensions can only be used as top-level declarations, this important feature of Swift could become more powerful and solve issues some users have with access control.

Swift-evolution thread: Enhancing access levels without breaking changes <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170403/035319.html>
<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#motivation>Motivation

Currently, access control is a very hot topic for Swift, and all of the options discussed so far had strong resistance from different parts of the community.

This concept tries to avoid all objections that were raised against the various modells (of course, it triggers fresh ones at the same time ;-), and because it is purely additive, it removes the pressure to address the current issues in Swift 4. Although it wasn't a motivation, the proposal also offers an answer to the question if (and how) properties should be allowed in extensions.

SE-0169 would render major parts of this idea useless, so I think it's qualified to be discussed in this stage.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#proposed-solution>Proposed solution

Simply remove the restriction that extensions can only be declared on top-level of a file.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#detailed-design>Detailed design

There isn't much to add here: Extensions should be allowed in type declarations and other extensions (I'm skipping methods in this draft - I see neither big problems associated with extensions declared inside methods, nor convincing use cases for them).

The rules should be the same as for nested types, so marking a member of an extension private would restrict its visiblity to the scope of this extension.

The goals of SE-0169 could be achieved in this model by simply putting an extension inside a type declaration, while keeping private members protected.

Nested extensions should also be allowed to contain stored properties of the enclosing class, thus enabling better visibility management for those as well:

Stored properties in extensions have been requested before, but this approach enables them quite naturally, as the rule that you can only declare stored properties inside the declaration of a type is respected.

It would also be possible to levearage the "default access level" feature of extensions to group properties that should have the same visibility.

Because there is no natural limit of nesting extensions, this feature enables developers to design more sophisticated systems of access rights, without increasing Swifts complexity for users that are happy with "puplic-internal-private" and don't see the need for additional keywords or other changes in the language.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#future-enhancements>Future enhancements

For extensions of an enclosing type, that type could be easily inferred, so some repetition could be eliminated easily.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#source-compatibility>Source compatibility

Purely additive

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#effect-on-abi-stability>Effect on ABI stability

There are some pitfalls associated with ABI, but I don't think its stability would be affected.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#effect-on-api-resilience>Effect on API resilience

Nono known

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#alternatives-considered>Alternatives considered

SE-0169, SE-0159, renaming "fileprivate" and/or "private"

All of those possibilities have their own strengths and weaknesses, and there is a huge dissent which of those are important: No matter which would be choosen, at least one group of Swift users is punished.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Xiaodi Wu) #4

As I've mentioned three or four times already on this list, every time this
issue is brought up, the rules of access modifiers as revised in SE-0025
*cannot accommodate* non-top level extensions.

This is because an extension is not--and the core team is not willing to
change this despite several draft proposals--a first-class entity. The
access modifier for an extension indicates the default visibility for its
members but is not an upper bound, because a non-entity cannot bound its
members. Instead, it is an error to include anything with a higher access
modifier inside an extension.

The way this works with "private extension" is that enclosed members are
"fileprivate" by default. This only works because an extension is
guaranteed to be top level, and thus private is equal to fileprivate.

If an extension is not top level, then there is no way to spell the default
access level of a modifier inside a private extension. Therefore, the rules
for access modifiers in extensions need to be changed in order for your
proposal to be viable. You must detail how you propose to change them. I
should add, previous attempts to do so during the end of Swift 3 evolution
were not even allowed to come to review.

···

On Fri, Apr 14, 2017 at 04:40 Tino Heth via swift-evolution < swift-evolution@swift.org> wrote:

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#introduction>
Introduction

By removing the restriction that extensions can only be used as top-level
declarations, this important feature of Swift could become more powerful
and solve issues some users have with access control.

Swift-evolution thread: Enhancing access levels without breaking changes
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170403/035319.html>

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#motivation>
Motivation

Currently, access control is a very hot topic for Swift, and all of the
options discussed so far had strong resistance from different parts of the
community.

This concept tries to avoid all objections that were raised against the
various modells (of course, it triggers fresh ones at the same time ;-),
and because it is purely additive, it removes the pressure to address the
current issues in Swift 4. Although it wasn't a motivation, the proposal
also offers an answer to the question if (and how) properties should be
allowed in extensions.

SE-0169 would render major parts of this idea useless, so I think it's
qualified to be discussed in this stage.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#proposed-solution>Proposed
solution

Simply remove the restriction that extensions can only be declared on
top-level of a file.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#detailed-design>Detailed
design

There isn't much to add here: Extensions should be allowed in type
declarations and other extensions (I'm skipping methods in this draft - I
see neither big problems associated with extensions declared inside
methods, nor convincing use cases for them).

   -

   The rules should be the same as for nested types, so marking a member
   of an extension private would restrict its visiblity to the scope of this
   extension.
   -

   The goals of SE-0169 could be achieved in this model by simply putting
   an extension inside a type declaration, while keeping private members
   protected.

Nested extensions should also be allowed to contain stored properties of
the enclosing class, thus enabling better visibility management for those
as well:

   -

   Stored properties in extensions have been requested before, but this
   approach enables them quite naturally, as the rule that you can only
   declare stored properties inside the declaration of a type is respected.
   -

   It would also be possible to levearage the "default access level"
   feature of extensions to group properties that should have the same
   visibility.

Because there is no natural limit of nesting extensions, this feature
enables developers to design more sophisticated systems of access rights,
without increasing Swifts complexity for users that are happy with
"puplic-internal-private" and don't see the need for additional keywords or
other changes in the language.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#future-enhancements>Future
enhancements

For extensions of an enclosing type, that type could be easily inferred,
so some repetition could be eliminated easily.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#source-compatibility>Source
compatibility

Purely additive

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#effect-on-abi-stability>Effect
on ABI stability

There are some pitfalls associated with ABI, but I don't think its
stability would be affected.

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#effect-on-api-resilience>Effect
on API resilience

Nono known

<https://github.com/tinoheth/swift-evolution/blob/NestedExtensions/0000-template.md#alternatives-considered>Alternatives
considered

SE-0169, SE-0159, renaming "fileprivate" and/or "private"
All of those possibilities have their own strengths and weaknesses, and
there is a huge dissent which of those are important: No matter which would
be choosen, at least one group of Swift users is punished.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Tony Arnold) #5

Hi Tino,

···

On 14 Apr 2017, at 19:40, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

This concept tries to avoid all objections that were raised against the various modells (of course, it triggers fresh ones at the same time ;-), and because it is purely additive, it removes the pressure to address the current issues in Swift 4.

Sorry to be a (hopefully polite) ogre, but from my perspective, your proposal does not address nor nullify the issues with access modifier levels in Swift, and I don’t think you should be pitching it as a stop-gap. It could make the use of extensions consistent with other similar declarations, but ultimately the access modifier level issues remain.

My questions:

- Can you clarify for me: does this proposal suggest allowing extensions on the enclosing type to be nested within the type declaration, or within other extensions on the original type? If so, can you please word that more clearly.

- I would like to see some examples of the proposed syntax included in your proposal (perhaps via a link to the markdown source on GitHub?). Best case and worst case examples would show what impact it will have on readability and file length when someone goes a bit nuts with this feature.

- Do you know how much work will be required to implement this change at this stage? Is it feasible within the bounds of the time remaining before Swift 4’s release?

————

Off-topic suggestion: Using the words “Simply” or “just” when describing work to be done by others is something that you should avoid (unless you’ve already implemented the feature and there’s a PR sitting on GitHub, ready to go). Removing those words allows the sentences to communicate the same ideas, but they no longer trivialise the size/scope of the work to be done during implementation.

————

At this stage, I’m really not sure whether I’d add my support for this proposal were it to go to review, but hopefully my comments are useful.

Cheers,

Tony

----------
Tony Arnold
+61 411 268 532
http://thecocoabots.com/

ABN: 14831833541


(Tino) #6

Hi Tony,

Sorry to be a (hopefully polite) ogre, but from my perspective, your proposal does not address nor nullify the issues with access modifier levels in Swift, and I don’t think you should be pitching it as a stop-gap. It could make the use of extensions consistent with other similar declarations, but ultimately the access modifier level issues remain.

Maybe this will be the case forever: Some people seem to have an affection for such things that goes far beyond my personal requirements, so I have no idea what someone else might come up with (I've already been joking about "cryptographic inheritance", which would allow you to override something only if you know the right transformation for the checksum of your new implementation ;-).
None the less, the concept is the most versatile I've have seen so far, yet it is less complex than some alternatives.

Right now, you can have your private properties in type declarations and extensions protected from all other types and extensions in the same file, and people say they want to have this option, so SE-0169 would hurt them.
Other people want same-file extensions to share private parts, and, at the same time, hide them from alien types in the same file (therefor, they don't want to use fileprivate).
Those two standpoints could coexist in Swift if we added another access modifier, but even if someone has a better name than "fileprivateButVisibleToSameTypeExtensionsInThisFile", this wouldn't be that nice…

Nested extensions, on the other hand, would require no new modifiers (actually, it would render fileprivate superfluous), and all you would have to do to have the effect of SE-0169 would be putting your extensions between an existing pair of curly braces, instead of placing them below that block.
I don't know about your specific issues with access levels, but the ones I have read about can be solved.

- Can you clarify for me: does this proposal suggest allowing extensions on the enclosing type to be nested within the type declaration, or within other extensions on the original type? If so, can you please word that more clearly.

Both: Whatever is possible outside the curly braces should be possible between them as well (at least I have no spontaneous example for something that should be forbidden).

- I would like to see some examples of the proposed syntax included in your proposal (perhaps via a link to the markdown source on GitHub?). Best case and worst case examples would show what impact it will have on readability and file length when someone goes a bit nuts with this feature.

No rules will stop people doing stupid things, but I'd rather give the people a tool they could use to harm their codebase, instead of bugging all users of Swift by trying to make it foolproof.
The linked discussion has an example - I'll attach it here as well, because the HTML has no syntax colouring :wink:

- Do you know how much work will be required to implement this change at this stage? Is it feasible within the bounds of the time remaining before Swift 4’s release?

Well, one major positive aspect of the idea is that there is no need to hurry:
I have an impression that we are in danger to make decisions without taking enough time to think about their consequences, just because a proposal should be part of the next release.
Nested extensions wouldn't break anything, so we could just leave this topic alone for now and include it in Swift 5 or 6 — or never, I someone has a better idea in the meantime.
SE-0169, on the other hand, would be yet another breaking change, and some people think it would harm Swift 4 and possible all versions to come after...

Off-topic suggestion: Using the words “Simply” or “just” when describing work to be done by others is something that you should avoid (unless you’ve already implemented the feature and there’s a PR sitting on GitHub, ready to go). Removing those words allows the sentences to communicate the same ideas, but they no longer trivialise the size/scope of the work to be done during implementation.

Oh yes, especially that last one — I did not find the fitting word yet, but I have to agree that this part could be interpreted in a way that wasn't intended.

At this stage, I’m really not sure whether I’d add my support for this proposal were it to go to review, but hopefully my comments are useful.

Well, I expected little more than a handful of comments saying "I like X better" and general disregard, so "I might support it" is already quite positive :wink:

- Tino

class MyVC: UIViewController {
    private let numberOfSections = 0

    extension: UITableViewDataSource {
        // Skipping the class and assume we want to extend the surrounding type
        func numberOfSections(in tableView: UITableView) -> Int {
            return numberOfSections
        }

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 0
        }
    }

    private extension {
        // this would contain everything that shoudn't be visible for other extensios

        var secret: Int = 0

        public extension MyFriendClass {
            // oh, well, I make an exception here for a trustworthy type
            func checkSecret(of controller: MyVC) -> Bool {
                return controller.secret > 0
            }
        }

        private extension {
            // this is so secret, I'm not even allowed to copy it
        }
    }

    public func myMethod() {
        print("This is just a boring method")
    }
}

It has the downside of shifting code to the right (you could as well leave those extension-blocks unindented), but lots of advantages:
- No change for private needed
- It can be nested as much as you like to satisfy even the most absurd desires of encapsulation
- It reminds me on operator definitions inside type declarations
- No change for fileprivate needed (but actually, I think there is very little need to keep fileprivate)


(Tino) #7

As I've mentioned three or four times already on this list, every time this issue is brought up, the rules of access modifiers as revised in SE-0025 *cannot accommodate* non-top level extensions.

Sorry to bother you, but do you have a string to search for, or can forward a mail that's part of of one of those threads that haven't been allowed to be reviewed?
Afair, there even was a review for a proposal that wanted to fully revert SE-0025, so I wonder why it should be forbidden to question parts of it?


(Xiaodi Wu) #8

Sure:

One solution to the problem is to remove the use of access modifiers as a
shorthand in front of extensions. It was proposed, reviewed, and rejected:
https://github.com/apple/swift-evolution/blob/master/proposals/0119-extensions-access-modifiers.md

The discussion was here:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160711/024224.html

I tried to follow up with a much milder proposal to change the rules
surrounding access modifiers. It was discussed here:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/024588.html

The PR was here, but rejected for review by the core team:
https://github.com/apple/swift-evolution/pull/438/files

···

On Fri, Apr 14, 2017 at 1:04 PM, Tino Heth <2th@gmx.de> wrote:

As I've mentioned three or four times already on this list, every time
this issue is brought up, the rules of access modifiers as revised in
SE-0025 *cannot accommodate* non-top level extensions.

Sorry to bother you, but do you have a string to search for, or can
forward a mail that's part of of one of those threads that haven't been
allowed to be reviewed?
Afair, there even was a review for a proposal that wanted to fully revert
SE-0025, so I wonder why it should be forbidden to question parts of it?


(Tino) #9

Thank you for you comment, Xiaodi.

I understand the disappointment, but imho this proposal is quite different from the ideas that have been rejected, and I hope to be able to convey that standpoint:

One solution to the problem is to remove the use of access modifiers as a shorthand in front of extensions. It was proposed, reviewed, and rejected:
https://github.com/apple/swift-evolution/blob/master/proposals/0119-extensions-access-modifiers.mdThe rational for the rejection was that this proposal would eliminate the useful ability to apply access control to a batch of methods and properties.

This can't be a motivation to discard nested extensions — it does not try to remove batching of access control, but rather extend that ability to be used for stored properties.

I tried to follow up with a much milder proposal to change the rules surrounding access modifiers. It was discussed here:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/024588.html

The PR was here, but rejected for review by the core team:
https://github.com/apple/swift-evolution/pull/438/files

I don't think this has much similarity either:
I'm not trying to change extensions itself, but rather leverage their existing capabilities in a bigger context.

To make it clear:
A private extension that is nested would would be completely inaccessible (and therefor useless) unless you have at least one member in it whose access level is set to internal (or more accessible).


(Xiaodi Wu) #10

I think you misunderstand. The rules of access modifiers do not currently
work with nested extensions without modification. How do you intend to
modify the rules? Previous attempts to do so, which were in part to make
possible nested extensions, were rejected.

···

On Sat, Apr 15, 2017 at 02:41 Tino Heth <2th@gmx.de> wrote:

Thank you for you comment, Xiaodi.

I understand the disappointment, but imho this proposal is quite different
from the ideas that have been rejected, and I hope to be able to convey
that standpoint:

One solution to the problem is to remove the use of access modifiers as a
shorthand in front of extensions. It was proposed, reviewed, and rejected:

https://github.com/apple/swift-evolution/blob/master/proposals/0119-extensions-access-modifiers.md

The rational for the rejection was that this proposal would eliminate *the
useful ability to apply access control to a batch of methods and
properties.*
This can't be a motivation to discard nested extensions — it does not try
to remove batching of access control, but rather extend that ability to be
used for stored properties.

I tried to follow up with a much milder proposal to change the rules
surrounding access modifiers. It was discussed here:

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/024588.html

The PR was here, but rejected for review by the core team:
https://github.com/apple/swift-evolution/pull/438/files

I don't think this has much similarity either:
I'm not trying to change extensions itself, but rather leverage their
existing capabilities in a bigger context.

To make it clear:
A private extension that is nested would would be completely inaccessible
(and therefor useless) unless you have at least one member in it whose
access level is set to internal (or more accessible).


(Tino) #11

I think you misunderstand. The rules of access modifiers do not currently work with nested extensions without modification. How do you intend to modify the rules?

There are no nested extensions now, right? So there are also no rules for their access modifiers, if I'm not missing something fundamental (which might be the case — please elaborate on this if my assumptions are wrong).

Afaik, the ideas you mentioned wanted to change how access modifiers of extensions work, whereas I don't want to change any of their rules.
I even don't want to add any new rules:
Just like today, an extension would introduce a separate scope, and the only meaning of its access modifier would be to act as the default for all elements of this extension.

The single change for nested extensions compared to regular ones would be the treatment of private (which changes the default for members to fileprivate, so it's rather inconsistent anyways, and not a real new rule, but rather removal of an exception).
This change wouldn't be necessary, but it would be inconvenient to manually mark the majority of its members as private.


(Xiaodi Wu) #12

I think you misunderstand how access modifiers currently work with
extensions. It is not permitted to use an access modifier inside an
extension that is higher than that of the extension itself. I pushed for
this rule not to be the case, in SE-0025, and in subsequent discussions, as
you saw. That was not accepted. Therefore:

private extension Foo {
  internal func bar() { } // this is a compiler error, because internal >
top-level private
}

It is not an exception to default members to `fileprivate` inside a
`private` extension. It is the only solution, but it only works for top
level extensions:

private extension Baz {
  fileprivate func boo() { } // this is allowed, because fileprivate ==
top-level private
}

There is no way to spell the access level of a nested private extension:

private struct S {
  private extension {
    func f() { } // what is the access level of `f`?
  }
}

If `f` is private, then it is invisible outside the extension. But `f`
cannot be `fileprivate`, because `fileprivate` is more visible than the
private extension and is therefore not allowed.

···

On Sat, Apr 15, 2017 at 10:23 AM, Tino Heth <2th@gmx.de> wrote:

> I think you misunderstand. The rules of access modifiers do not
currently work with nested extensions without modification. How do you
intend to modify the rules?
There are no nested extensions now, right? So there are also no rules for
their access modifiers, if I'm not missing something fundamental (which
might be the case — please elaborate on this if my assumptions are wrong).

Afaik, the ideas you mentioned wanted to change how access modifiers of
extensions work, whereas I don't want to change any of their rules.
I even don't want to add any new rules:
Just like today, an extension would introduce a separate scope, and the
only meaning of its access modifier would be to act as the default for all
elements of this extension.

The single change for nested extensions compared to regular ones would be
the treatment of private (which changes the default for members to
fileprivate, so it's rather inconsistent anyways, and not a real new rule,
but rather removal of an exception).
This change wouldn't be necessary, but it would be inconvenient to
manually mark the majority of its members as private.


(Tino) #13

I think you misunderstand how access modifiers currently work with extensions. It is not permitted to use an access modifier inside an extension that is higher than that of the extension itself.

class Check {}

fileprivate extension Check {
  public func px() {
    print("It compiles!")
  }
}

Check().px()

This code executes without complains — but your example is right, it fails if the extension is marked private… wtf? Access modifiers aren't even mentioned in https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html#//apple_ref/doc/uid/TP40014097-CH24-ID151

It really seems to me that the current extension-model is somewhat broken; do you have a link to documentation of access levels for extensions?

private struct S {
  private extension {
    func f() { } // what is the access level of `f`?
  }
}

If `f` is private, then it is invisible outside the extension. But `f` cannot be `fileprivate`, because `fileprivate` is more visible than the private extension and is therefore not allowed.

I'd simply say f is private and only visible inside the extension…

···

Am 15.04.2017 um 17:33 schrieb Xiaodi Wu <xiaodi.wu@gmail.com>:


(Xiaodi Wu) #14

The rules are laid out in SE-0025. What you are finding is that SE-0025 is
not yet fully implemented.

···

On Sat, Apr 15, 2017 at 11:04 Tino Heth <2th@gmx.de> wrote:

Am 15.04.2017 um 17:33 schrieb Xiaodi Wu <xiaodi.wu@gmail.com>:

I think you misunderstand how access modifiers currently work with
extensions. It is not permitted to use an access modifier inside an
extension that is higher than that of the extension itself.

class Check {}

fileprivate extension Check {
public func px() {
print("It compiles!")
}
}

Check().px()

This code executes without complains — but your example is right, it fails
if the extension is marked private… wtf? Access modifiers aren't even
mentioned in
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html#//apple_ref/doc/uid/TP40014097-CH24-ID151

It really seems to me that the current extension-model is somewhat broken;
do you have a link to documentation of access levels for extensions?

private struct S {
  private extension {
    func f() { } // what is the access level of `f`?
  }
}

If `f` is private, then it is invisible outside the extension. But `f`
cannot be `fileprivate`, because `fileprivate` is more visible than the
private extension and is therefore not allowed.

I'd simply say f is private and only visible inside the extension…


(Xiaodi Wu) #15

The current rules in SE-0025 state that the access modifier in front of the
extension states both the default and the maximum allowed visibility. This
is what I was trying to change.

If private extension means that all members inside are by default and at
maximum only visible inside the extension, then every private extension
would be equivalent to `private extension Foo { }`. That is not useful, so
it is understood that private extension means private to the _containing_
scope. But the containing scope only has a name if the extension exists at
the top level.

···

On Sat, Apr 15, 2017 at 11:26 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

The rules are laid out in SE-0025. What you are finding is that SE-0025 is
not yet fully implemented.
On Sat, Apr 15, 2017 at 11:04 Tino Heth <2th@gmx.de> wrote:

Am 15.04.2017 um 17:33 schrieb Xiaodi Wu <xiaodi.wu@gmail.com>:

I think you misunderstand how access modifiers currently work with
extensions. It is not permitted to use an access modifier inside an
extension that is higher than that of the extension itself.

class Check {}

fileprivate extension Check {
public func px() {
print("It compiles!")
}
}

Check().px()

This code executes without complains — but your example is right, it
fails if the extension is marked private… wtf? Access modifiers aren't even
mentioned in
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html#//apple_ref/doc/uid/TP40014097-CH24-ID151

It really seems to me that the current extension-model is somewhat
broken; do you have a link to documentation of access levels for extensions?

private struct S {
  private extension {
    func f() { } // what is the access level of `f`?
  }
}

If `f` is private, then it is invisible outside the extension. But `f`
cannot be `fileprivate`, because `fileprivate` is more visible than the
private extension and is therefore not allowed.

I'd simply say f is private and only visible inside the extension…


(Tino) #16

The current rules in SE-0025 state that the access modifier in front of the extension states both the default and the maximum allowed visibility. This is what I was trying to change.

Oh dear!
But afaics, SE-0025 is not to blame for all those complications, and many problems have a different origin… did you encounter any serious counter arguments to reduce the rules for access modifiers on extensions to "it sets the default for all entities contained in the extension"?
I think I'll do a PR despite those issues — changing the rules to allow nesting wasn't accepted, but maybe introduce nesting to change the rules works out :wink: