Type access level as the default for its members?


(Eric-Paul Lecluse) #1

To illustrate my question below, here are three publicly modified entities:
a struct, an enum and an extension, whose properties lack explicit access
modifiers:

    public struct Car {
        var wheel: [Wheel]
        var licensePlate: String

        func combust() { ... }
    }

    public enum Wheel {
        case big
        case small

        var revolutionDistance: Double { ... }
    }

    public extension Car {
        func park() { ... }
    }

The default access level for every member is `internal` for all members of
an original type. Therefore both `combust()` and `revolutionDistance` are
publicly inaccessible. For extensions, this is different, `park()` _is_
publicly accessible (as would be computed properties if it had any) because
the extension is marked `public`. There's no option to modify an enum's
cases individually (nor should there be), they're inherently linked to the
enum's access level.

When modifying any of the entities to `private`, their members become
inaccessible by association. If a type isn't accessible, neither are its
members. Thus for the `private` case, the behavior feels more like what the
extension modifier did in the first place.

Not immediately apparent from this example is that the struct has an
implicit constructor (lacking any explicit ones), whose access level also
defaults to `internal`. This means the Car-struct can't be constructed
outside of its defining module, until we create an explicit initializer
with the `public` access modifier.

# Problems
The current approach is very verbose for any kind of access modification.
Public structs that are intended to expose their members, require
explicitly marked `public` modifiers everywhere. Consider the case where
you want to expose a previously hidden (internal or private) type, you need
to modify every individual member. Except if you're modifying an extension,
in that case you only need to modify in one place. This means that
conceptually, putting a `public` or `private` modifier on a type behaves
differently from putting one one an extension, with regard to a type's
members, which can lead to confusion (and has in my case, and with several
fellow developers).

# Idea
What if the default access level were chosen differently? Instead of being
`internal` by default, or `private` by association, what if the
_type-level_ access modifier would determine the default for _all_ members,
unless explicitly modified, including `public` and to-be-introduced ones?

This would...
1. equalize the conceptual behavior between access levels of an original
type and the ones of their extensions.
2. greatly reduce verbosity on members due to explicit access level
modifiers.
3. make it easier to modify the access level of an entire type, without
requiring modification of individual members.
4. reduce the requirement of public constructors where they would match the
implicit ones.
5. still allow exceptions on an individual level

What do you think?
Regards,
Eric-Paul

···

--
Notes:
* I'm using the word 'entity' to lump types and extensions together under
one term. There must be a better term, please do share!
* My examples are based off of my experience with Swift 2.2, even though I
believe the concepts still apply in 2.3 and the 3.0-beta.
* Protocols don't allow access modification on individual members, of
course, similar to an enum's cases.
* Didn't find any similar topics in the [commonly rejected list](
https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md)
* There's a [newly accepted proposal](
https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md#proposed-solution)
that adds `fileprivate` as a fourth access level modifier.

Other discussions about access levels, yet not what I was looking for:
* [Default access control / Access control blocks] (
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160328/013683.html
)
* [Access modifier blocks] (
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160613/020968.html
)


(Chéyo Jiménez) #2

To illustrate my question below, here are three publicly modified entities: a struct, an enum and an extension, whose properties lack explicit access modifiers:

    public struct Car {
        var wheel: [Wheel]
        var licensePlate: String
       
        func combust() { ... }
    }
    
    public enum Wheel {
        case big
        case small
        
        var revolutionDistance: Double { ... }
    }

    public extension Car {
        func park() { ... }
    }

The default access level for every member is `internal` for all members of an original type. Therefore both `combust()` and `revolutionDistance` are publicly inaccessible. For extensions, this is different, `park()` _is_ publicly accessible (as would be computed properties if it had any) because the extension is marked `public`. There's no option to modify an enum's cases individually (nor should there be), they're inherently linked to the enum's access level.

When modifying any of the entities to `private`, their members become inaccessible by association. If a type isn't accessible, neither are its members. Thus for the `private` case, the behavior feels more like what the extension modifier did in the first place.

Not immediately apparent from this example is that the struct has an implicit constructor (lacking any explicit ones), whose access level also defaults to `internal`. This means the Car-struct can't be constructed outside of its defining module, until we create an explicit initializer with the `public` access modifier.

# Problems
The current approach is very verbose for any kind of access modification. Public structs that are intended to expose their members, require explicitly marked `public` modifiers everywhere. Consider the case where you want to expose a previously hidden (internal or private) type, you need to modify every individual member. Except if you're modifying an extension, in that case you only need to modify in one place. This means that conceptually, putting a `public` or `private` modifier on a type behaves differently from putting one one an extension, with regard to a type's members, which can lead to confusion (and has in my case, and with several fellow developers).

# Idea
What if the default access level were chosen differently? Instead of being `internal` by default, or `private` by association, what if the _type-level_ access modifier would determine the default for _all_ members, unless explicitly modified, including `public` and to-be-introduced ones?

I don't think this is going fly:
- internal is the default because the team wants any public API to be explicit.
- There was a rejected proposal (119?) that tried to make extensions work just like types.
- This is a breaking change and we are out of time for swift3
- What you want is already offered by public extensions. (Some people find this confusing but it looks like this is stay in swift 3).

···

On Jul 22, 2016, at 3:34 AM, Eric-Paul Lecluse via swift-evolution <swift-evolution@swift.org> wrote:

This would...
1. equalize the conceptual behavior between access levels of an original type and the ones of their extensions.
2. greatly reduce verbosity on members due to explicit access level modifiers.
3. make it easier to modify the access level of an entire type, without requiring modification of individual members.
4. reduce the requirement of public constructors where they would match the implicit ones.
5. still allow exceptions on an individual level

What do you think?
Regards,
Eric-Paul

--
Notes:
* I'm using the word 'entity' to lump types and extensions together under one term. There must be a better term, please do share!
* My examples are based off of my experience with Swift 2.2, even though I believe the concepts still apply in 2.3 and the 3.0-beta.
* Protocols don't allow access modification on individual members, of course, similar to an enum's cases.
* Didn't find any similar topics in the [commonly rejected list](https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md)
* There's a [newly accepted proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md#proposed-solution) that adds `fileprivate` as a fourth access level modifier.

Other discussions about access levels, yet not what I was looking for:
* [Default access control / Access control blocks] (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160328/013683.html)
* [Access modifier blocks] (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160613/020968.html)
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Félix Cloutier) #3

The only point that judges the proposal on its merits would be the first one, and I would personally be happy to have that discussion.

Félix

···

Le 22 juil. 2016 à 10:14:13, Jose Cheyo Jimenez via swift-evolution <swift-evolution@swift.org> a écrit :

On Jul 22, 2016, at 3:34 AM, Eric-Paul Lecluse via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

To illustrate my question below, here are three publicly modified entities: a struct, an enum and an extension, whose properties lack explicit access modifiers:

    public struct Car {
        var wheel: [Wheel]
        var licensePlate: String
       
        func combust() { ... }
    }
    
    public enum Wheel {
        case big
        case small
        
        var revolutionDistance: Double { ... }
    }

    public extension Car {
        func park() { ... }
    }

The default access level for every member is `internal` for all members of an original type. Therefore both `combust()` and `revolutionDistance` are publicly inaccessible. For extensions, this is different, `park()` _is_ publicly accessible (as would be computed properties if it had any) because the extension is marked `public`. There's no option to modify an enum's cases individually (nor should there be), they're inherently linked to the enum's access level.

When modifying any of the entities to `private`, their members become inaccessible by association. If a type isn't accessible, neither are its members. Thus for the `private` case, the behavior feels more like what the extension modifier did in the first place.

Not immediately apparent from this example is that the struct has an implicit constructor (lacking any explicit ones), whose access level also defaults to `internal`. This means the Car-struct can't be constructed outside of its defining module, until we create an explicit initializer with the `public` access modifier.

# Problems
The current approach is very verbose for any kind of access modification. Public structs that are intended to expose their members, require explicitly marked `public` modifiers everywhere. Consider the case where you want to expose a previously hidden (internal or private) type, you need to modify every individual member. Except if you're modifying an extension, in that case you only need to modify in one place. This means that conceptually, putting a `public` or `private` modifier on a type behaves differently from putting one one an extension, with regard to a type's members, which can lead to confusion (and has in my case, and with several fellow developers).

# Idea
What if the default access level were chosen differently? Instead of being `internal` by default, or `private` by association, what if the _type-level_ access modifier would determine the default for _all_ members, unless explicitly modified, including `public` and to-be-introduced ones?

I don't think this is going fly:
- internal is the default because the team wants any public API to be explicit.
- There was a rejected proposal (119?) that tried to make extensions work just like types.
- This is a breaking change and we are out of time for swift3
- What you want is already offered by public extensions. (Some people find this confusing but it looks like this is stay in swift 3).

This would...
1. equalize the conceptual behavior between access levels of an original type and the ones of their extensions.
2. greatly reduce verbosity on members due to explicit access level modifiers.
3. make it easier to modify the access level of an entire type, without requiring modification of individual members.
4. reduce the requirement of public constructors where they would match the implicit ones.
5. still allow exceptions on an individual level

What do you think?
Regards,
Eric-Paul

--
Notes:
* I'm using the word 'entity' to lump types and extensions together under one term. There must be a better term, please do share!
* My examples are based off of my experience with Swift 2.2, even though I believe the concepts still apply in 2.3 and the 3.0-beta.
* Protocols don't allow access modification on individual members, of course, similar to an enum's cases.
* Didn't find any similar topics in the [commonly rejected list](https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md)
* There's a [newly accepted proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md#proposed-solution) that adds `fileprivate` as a fourth access level modifier.

Other discussions about access levels, yet not what I was looking for:
* [Default access control / Access control blocks] (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160328/013683.html)
* [Access modifier blocks] (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160613/020968.html)
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Chéyo Jiménez) #4

The only point that judges the proposal on its merits would be the first one, and I would personally be happy to have that discussion.

https://github.com/apple/swift-evolution/pull/438

I think that battle is lost for now.

···

On Jul 22, 2016, at 7:05 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

Félix

Le 22 juil. 2016 à 10:14:13, Jose Cheyo Jimenez via swift-evolution <swift-evolution@swift.org> a écrit :

On Jul 22, 2016, at 3:34 AM, Eric-Paul Lecluse via swift-evolution <swift-evolution@swift.org> wrote:

To illustrate my question below, here are three publicly modified entities: a struct, an enum and an extension, whose properties lack explicit access modifiers:

    public struct Car {
        var wheel: [Wheel]
        var licensePlate: String
       
        func combust() { ... }
    }
    
    public enum Wheel {
        case big
        case small
        
        var revolutionDistance: Double { ... }
    }

    public extension Car {
        func park() { ... }
    }

The default access level for every member is `internal` for all members of an original type. Therefore both `combust()` and `revolutionDistance` are publicly inaccessible. For extensions, this is different, `park()` _is_ publicly accessible (as would be computed properties if it had any) because the extension is marked `public`. There's no option to modify an enum's cases individually (nor should there be), they're inherently linked to the enum's access level.

When modifying any of the entities to `private`, their members become inaccessible by association. If a type isn't accessible, neither are its members. Thus for the `private` case, the behavior feels more like what the extension modifier did in the first place.

Not immediately apparent from this example is that the struct has an implicit constructor (lacking any explicit ones), whose access level also defaults to `internal`. This means the Car-struct can't be constructed outside of its defining module, until we create an explicit initializer with the `public` access modifier.

# Problems
The current approach is very verbose for any kind of access modification. Public structs that are intended to expose their members, require explicitly marked `public` modifiers everywhere. Consider the case where you want to expose a previously hidden (internal or private) type, you need to modify every individual member. Except if you're modifying an extension, in that case you only need to modify in one place. This means that conceptually, putting a `public` or `private` modifier on a type behaves differently from putting one one an extension, with regard to a type's members, which can lead to confusion (and has in my case, and with several fellow developers).

# Idea
What if the default access level were chosen differently? Instead of being `internal` by default, or `private` by association, what if the _type-level_ access modifier would determine the default for _all_ members, unless explicitly modified, including `public` and to-be-introduced ones?

I don't think this is going fly:
- internal is the default because the team wants any public API to be explicit.
- There was a rejected proposal (119?) that tried to make extensions work just like types.
- This is a breaking change and we are out of time for swift3
- What you want is already offered by public extensions. (Some people find this confusing but it looks like this is stay in swift 3).

This would...
1. equalize the conceptual behavior between access levels of an original type and the ones of their extensions.
2. greatly reduce verbosity on members due to explicit access level modifiers.
3. make it easier to modify the access level of an entire type, without requiring modification of individual members.
4. reduce the requirement of public constructors where they would match the implicit ones.
5. still allow exceptions on an individual level

What do you think?
Regards,
Eric-Paul

--
Notes:
* I'm using the word 'entity' to lump types and extensions together under one term. There must be a better term, please do share!
* My examples are based off of my experience with Swift 2.2, even though I believe the concepts still apply in 2.3 and the 3.0-beta.
* Protocols don't allow access modification on individual members, of course, similar to an enum's cases.
* Didn't find any similar topics in the [commonly rejected list](https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md)
* There's a [newly accepted proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md#proposed-solution) that adds `fileprivate` as a fourth access level modifier.

Other discussions about access levels, yet not what I was looking for:
* [Default access control / Access control blocks] (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160328/013683.html)
* [Access modifier blocks] (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160613/020968.html)
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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