SE-0025: Scoped Access Level, next steps


(Jon Hull) #1

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current “private(set)"
private(get: module, set: file) //getter has module scope & setter has file scope

It is a bit weird, but we should probably also allow “public" in that last form: private(get: public, set: module)

Thanks,
Jon

···

On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.


(Patrick Pijnappel) #2

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets too
inconsistent with private(set: public) and private(set: private) (?!)

···

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution < swift-evolution@swift.org> wrote:

*On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:*

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current
“private(set)"
private(get: module, set: file) //getter has module scope & setter has
file scope

It is a bit weird, but we should probably also allow “public" in that last
form: private(get: public, set: module)

Thanks,
Jon

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


(Patrick Pijnappel) #3

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

···

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel < patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets
too inconsistent with private(set: public) and private(set: private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution < > swift-evolution@swift.org> wrote:

*On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:*

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current
“private(set)"
private(get: module, set: file) //getter has module scope & setter has
file scope

It is a bit weird, but we should probably also allow “public" in that
last form: private(get: public, set: module)

Thanks,
Jon

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


(Jon Hull) #4

And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom getter/setter implementations. We should definitely be able to do:

var foo:Int {
  public get {…}
  private(file) set {…}
}

In fact, that is what I first tried to do before learning about private(set). But without the implementations, it just seems strange to put the scoping after the rest of the declaration (they work above because they are before the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter, that might work too. I don’t love it, but maybe with better wording?

var foo:Int{
  public get useDefault
  private(file) set {…}
}

Thanks,
Jon

···

On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel <patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel <patrickpijnappel@gmail.com <mailto:patrickpijnappel@gmail.com>> wrote:
I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets too inconsistent with private(set: public) and private(set: private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current “private(set)"
private(get: module, set: file) //getter has module scope & setter has file scope

It is a bit weird, but we should probably also allow “public" in that last form: private(get: public, set: module)

Thanks,
Jon

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


(Ross O'Brien) #5

It's occurring to me, reading these recent posts, that we have two
orthogonal systems of access levels.

Swift's current access system is file based; a project file decides which
files comprise a module, and the terms 'public', 'internal' and 'private'
determine whether a property is accessible to all, accessible only within
files of the module, or accessible only within a file. (This takes on an
extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed
concepts in this discussion, ask instead for a type-based access system
similar to those in other languages including Objective-C, where 'public',
'protected' and 'private' are the terms of choice and they restrict access
to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in the
file-based access system and 'private' to a concept in the type-based
access system.

I would prefer clearer terms which actually mention the restrictions of the
level. For example, 'inherited', not 'protected', in the case of properties
accessible by a class and its subclasses; 'declaration', rather than
'private' or 'scoped', to refer to properties only accessible within a
given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I think
this most-restricted level has managed to pass as a level of the file-based
access system. However, if the system is ever extended, we're going to run
into new syntax decisions where we have 'private module' functions
(accessible only within the given type in the same module) trying to
communicate with 'protected file' properties (accessible only with the type
and its subtypes in the same file), and that might lead to conflicts, so
perhaps we should decide how those might be declared now.

···

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution < swift-evolution@swift.org> wrote:

On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom
getter/setter implementations. We should definitely be able to do:

var foo:Int {
public get {…}
private(file) set {…}
}

In fact, that is what I first tried to do before learning about
private(set). But without the implementations, it just seems strange to
put the scoping after the rest of the declaration (they work above because
they are *before* the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax
for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter, that
might work too. I don’t love it, but maybe with better wording?

var foo:Int{
public get useDefault
private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel < > patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel < > patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets
too inconsistent with private(set: public) and private(set: private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution < >> swift-evolution@swift.org> wrote:

*On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:*

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current
“private(set)"
private(get: module, set: file) //getter has module scope & setter has
file scope

It is a bit weird, but we should probably also allow “public" in that
last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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


(Jordan Rose) #6

SE-0025 did not include any type-based access control. I personally would like to keep Swift free of type-based access control, and I think the core team feels the same way. "The world, the module, the file, the current lexical scope" is a properly nested set of scopes that are not defined in terms of types.

I think discussion of type-based access control should happen on a different thread. As you say, it would be orthogonal to any refinements of SE-0025.

Jordan

···

On Mar 15, 2016, at 17:26 , Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

It's occurring to me, reading these recent posts, that we have two orthogonal systems of access levels.

Swift's current access system is file based; a project file decides which files comprise a module, and the terms 'public', 'internal' and 'private' determine whether a property is accessible to all, accessible only within files of the module, or accessible only within a file. (This takes on an extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed concepts in this discussion, ask instead for a type-based access system similar to those in other languages including Objective-C, where 'public', 'protected' and 'private' are the terms of choice and they restrict access to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in the file-based access system and 'private' to a concept in the type-based access system.

I would prefer clearer terms which actually mention the restrictions of the level. For example, 'inherited', not 'protected', in the case of properties accessible by a class and its subclasses; 'declaration', rather than 'private' or 'scoped', to refer to properties only accessible within a given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I think this most-restricted level has managed to pass as a level of the file-based access system. However, if the system is ever extended, we're going to run into new syntax decisions where we have 'private module' functions (accessible only within the given type in the same module) trying to communicate with 'protected file' properties (accessible only with the type and its subtypes in the same file), and that might lead to conflicts, so perhaps we should decide how those might be declared now.

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom getter/setter implementations. We should definitely be able to do:

var foo:Int {
  public get {…}
  private(file) set {…}
}

In fact, that is what I first tried to do before learning about private(set). But without the implementations, it just seems strange to put the scoping after the rest of the declaration (they work above because they are before the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter, that might work too. I don’t love it, but maybe with better wording?

var foo:Int{
  public get useDefault
  private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel <patrickpijnappel@gmail.com <mailto:patrickpijnappel@gmail.com>> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel <patrickpijnappel@gmail.com <mailto:patrickpijnappel@gmail.com>> wrote:
I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets too inconsistent with private(set: public) and private(set: private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current “private(set)"
private(get: module, set: file) //getter has module scope & setter has file scope

It is a bit weird, but we should probably also allow “public" in that last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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

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


(Patrick Pijnappel) #7

Ok to summarize:

*Setter access modifiers*

var foo: Int { private set { ... } }

var foo: Int { private set }

   - Consistent with mutating set { ... }. Arguably the current private(set)
   is inconsistent.
   - Eliminates the odd corner case of having a double access modifier,
   e.g. public private(set) var foo: Int.
   - It's very sensible for custom getters/setters (top case), it just
   requires allowing a bodiless get/set. We already kinda do this in protocols.

*Access modifier keywords*

public/private(module)/private(file)/private

   - It's not clear from the keywords how restrictive local/private/internal
   are, while private(module) and private(file) are obvious. This
makes a declaration
   either public, or private to a certain scope. Arguably e.g.
   public/module/file/declaration has similar benefits but they aren't as
   clearly access control related as a keyword (e.g. module could just as
   well be declaring a module).
   - private(module) and private(file) are relatively long, but the longest
   – private(module) – is rarely used (outside the standard library) as
   it's the default. Most uses of the old private are more appropriately
   done using the new private, so private(file) would likely be used less
   than private.
   - The scheme expands very well to named submodules, e.g. if you have a
   submodule named model you might limit the scope using private(model).
   - private(file) as opposed to private-file or private/file makes it more
   consistent with the new function-like syntax for e.g. attributes.

···

On Wed, Mar 16, 2016 at 11:26 AM, Ross O'Brien via swift-evolution < swift-evolution@swift.org> wrote:

It's occurring to me, reading these recent posts, that we have two
orthogonal systems of access levels.

Swift's current access system is file based; a project file decides which
files comprise a module, and the terms 'public', 'internal' and 'private'
determine whether a property is accessible to all, accessible only within
files of the module, or accessible only within a file. (This takes on an
extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed
concepts in this discussion, ask instead for a type-based access system
similar to those in other languages including Objective-C, where 'public',
'protected' and 'private' are the terms of choice and they restrict access
to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in
the file-based access system and 'private' to a concept in the type-based
access system.

I would prefer clearer terms which actually mention the restrictions of
the level. For example, 'inherited', not 'protected', in the case of
properties accessible by a class and its subclasses; 'declaration', rather
than 'private' or 'scoped', to refer to properties only accessible within a
given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I
think this most-restricted level has managed to pass as a level of the
file-based access system. However, if the system is ever extended, we're
going to run into new syntax decisions where we have 'private module'
functions (accessible only within the given type in the same module) trying
to communicate with 'protected file' properties (accessible only with the
type and its subtypes in the same file), and that might lead to conflicts,
so perhaps we should decide how those might be declared now.

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution < > swift-evolution@swift.org> wrote:

On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom
getter/setter implementations. We should definitely be able to do:

var foo:Int {
public get {…}
private(file) set {…}
}

In fact, that is what I first tried to do before learning about
private(set). But without the implementations, it just seems strange to
put the scoping after the rest of the declaration (they work above because
they are *before* the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax
for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter, that
might work too. I don’t love it, but maybe with better wording?

var foo:Int{
public get useDefault
private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel < >> patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel < >> patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets
too inconsistent with private(set: public) and private(set: private)
(?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution < >>> swift-evolution@swift.org> wrote:

*On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:*

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current
“private(set)"
private(get: module, set: file) //getter has module scope & setter has
file scope

It is a bit weird, but we should probably also allow “public" in that
last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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

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


(David Hart) #8

Very good summary :slight_smile: I find this option very consistent +1

···

On 16 Mar 2016, at 07:49, Patrick Pijnappel via swift-evolution <swift-evolution@swift.org> wrote:

Ok to summarize:

Setter access modifiers
var foo: Int { private set { ... } }
var foo: Int { private set }
Consistent with mutating set { ... }. Arguably the current private(set) is inconsistent.
Eliminates the odd corner case of having a double access modifier, e.g. public private(set) var foo: Int.
It's very sensible for custom getters/setters (top case), it just requires allowing a bodiless get/set. We already kinda do this in protocols.

Access modifier keywords
public/private(module)/private(file)/private
It's not clear from the keywords how restrictive local/private/internal are, while private(module) and private(file) are obvious. This makes a declaration either public, or private to a certain scope. Arguably e.g. public/module/file/declaration has similar benefits but they aren't as clearly access control related as a keyword (e.g. module could just as well be declaring a module).
private(module) and private(file) are relatively long, but the longest – private(module) – is rarely used (outside the standard library) as it's the default. Most uses of the old private are more appropriately done using the new private, so private(file) would likely be used less than private.
The scheme expands very well to named submodules, e.g. if you have a submodule named model you might limit the scope using private(model).
private(file) as opposed to private-file or private/file makes it more consistent with the new function-like syntax for e.g. attributes.

On Wed, Mar 16, 2016 at 11:26 AM, Ross O'Brien via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
It's occurring to me, reading these recent posts, that we have two orthogonal systems of access levels.

Swift's current access system is file based; a project file decides which files comprise a module, and the terms 'public', 'internal' and 'private' determine whether a property is accessible to all, accessible only within files of the module, or accessible only within a file. (This takes on an extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed concepts in this discussion, ask instead for a type-based access system similar to those in other languages including Objective-C, where 'public', 'protected' and 'private' are the terms of choice and they restrict access to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in the file-based access system and 'private' to a concept in the type-based access system.

I would prefer clearer terms which actually mention the restrictions of the level. For example, 'inherited', not 'protected', in the case of properties accessible by a class and its subclasses; 'declaration', rather than 'private' or 'scoped', to refer to properties only accessible within a given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I think this most-restricted level has managed to pass as a level of the file-based access system. However, if the system is ever extended, we're going to run into new syntax decisions where we have 'private module' functions (accessible only within the given type in the same module) trying to communicate with 'protected file' properties (accessible only with the type and its subtypes in the same file), and that might lead to conflicts, so perhaps we should decide how those might be declared now.

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom getter/setter implementations. We should definitely be able to do:

var foo:Int {
  public get {…}
  private(file) set {…}
}

In fact, that is what I first tried to do before learning about private(set). But without the implementations, it just seems strange to put the scoping after the rest of the declaration (they work above because they are before the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter, that might work too. I don’t love it, but maybe with better wording?

var foo:Int{
  public get useDefault
  private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel <patrickpijnappel@gmail.com <mailto:patrickpijnappel@gmail.com>> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel <patrickpijnappel@gmail.com <mailto:patrickpijnappel@gmail.com>> wrote:
I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets too inconsistent with private(set: public) and private(set: private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current “private(set)"
private(get: module, set: file) //getter has module scope & setter has file scope

It is a bit weird, but we should probably also allow “public" in that last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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

_______________________________________________
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
https://lists.swift.org/mailman/listinfo/swift-evolution


(Goffredo Marocchi) #9

Great summary, but I would still use new keywords rather than adding modifiers to private itself.

public
module
file/ sourceFile /pick a better word :slight_smile:
private

···

Sent from my iPhone

On 16 Mar 2016, at 06:49, Patrick Pijnappel via swift-evolution <swift-evolution@swift.org> wrote:

Ok to summarize:

Setter access modifiers
var foo: Int { private set { ... } }
var foo: Int { private set }
Consistent with mutating set { ... }. Arguably the current private(set) is inconsistent.
Eliminates the odd corner case of having a double access modifier, e.g. public private(set) var foo: Int.
It's very sensible for custom getters/setters (top case), it just requires allowing a bodiless get/set. We already kinda do this in protocols.

Access modifier keywords
public/private(module)/private(file)/private
It's not clear from the keywords how restrictive local/private/internal are, while private(module) and private(file) are obvious. This makes a declaration either public, or private to a certain scope. Arguably e.g. public/module/file/declaration has similar benefits but they aren't as clearly access control related as a keyword (e.g. module could just as well be declaring a module).
private(module) and private(file) are relatively long, but the longest – private(module) – is rarely used (outside the standard library) as it's the default. Most uses of the old private are more appropriately done using the new private, so private(file) would likely be used less than private.
The scheme expands very well to named submodules, e.g. if you have a submodule named model you might limit the scope using private(model).
private(file) as opposed to private-file or private/file makes it more consistent with the new function-like syntax for e.g. attributes.

On Wed, Mar 16, 2016 at 11:26 AM, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:
It's occurring to me, reading these recent posts, that we have two orthogonal systems of access levels.

Swift's current access system is file based; a project file decides which files comprise a module, and the terms 'public', 'internal' and 'private' determine whether a property is accessible to all, accessible only within files of the module, or accessible only within a file. (This takes on an extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed concepts in this discussion, ask instead for a type-based access system similar to those in other languages including Objective-C, where 'public', 'protected' and 'private' are the terms of choice and they restrict access to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in the file-based access system and 'private' to a concept in the type-based access system.

I would prefer clearer terms which actually mention the restrictions of the level. For example, 'inherited', not 'protected', in the case of properties accessible by a class and its subclasses; 'declaration', rather than 'private' or 'scoped', to refer to properties only accessible within a given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I think this most-restricted level has managed to pass as a level of the file-based access system. However, if the system is ever extended, we're going to run into new syntax decisions where we have 'private module' functions (accessible only within the given type in the same module) trying to communicate with 'protected file' properties (accessible only with the type and its subtypes in the same file), and that might lead to conflicts, so perhaps we should decide how those might be declared now.

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote:

On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com> wrote:
And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom getter/setter implementations. We should definitely be able to do:

var foo:Int {
  public get {…}
  private(file) set {…}
}

In fact, that is what I first tried to do before learning about private(set). But without the implementations, it just seems strange to put the scoping after the rest of the declaration (they work above because they are before the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter, that might work too. I don’t love it, but maybe with better wording?

var foo:Int{
  public get useDefault
  private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel <patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel <patrickpijnappel@gmail.com> wrote:
I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets too inconsistent with private(set: public) and private(set: private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org> wrote:
The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current “private(set)"
private(get: module, set: file) //getter has module scope & setter has file scope

It is a bit weird, but we should probably also allow “public" in that last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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

_______________________________________________
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


(Haravikk) #10

I like the idea of repurposing brackets after private to do this. I think though that it might be better if there were also a private(type) option to allow us to be explicit about it, even if we can still type just private to use it by default.

About replacing private(set), the examples you’ve given look like computed properties, and being able to put the accessibility declaration before the setter is a good option, but for stored properties I think we also need a way to specify the restriction, for example private(file: set) to enable setting the value only at the file level. This means that private on its own is by default actually private(type: get set)

···

On 16 Mar 2016, at 06:49, Patrick Pijnappel via swift-evolution <swift-evolution@swift.org> wrote:

Ok to summarize:

Setter access modifiers
var foo: Int { private set { ... } }
var foo: Int { private set }
Consistent with mutating set { ... }. Arguably the current private(set) is inconsistent.
Eliminates the odd corner case of having a double access modifier, e.g. public private(set) var foo: Int.
It's very sensible for custom getters/setters (top case), it just requires allowing a bodiless get/set. We already kinda do this in protocols.

Access modifier keywords
public/private(module)/private(file)/private
It's not clear from the keywords how restrictive local/private/internal are, while private(module) and private(file) are obvious. This makes a declaration either public, or private to a certain scope. Arguably e.g. public/module/file/declaration has similar benefits but they aren't as clearly access control related as a keyword (e.g. module could just as well be declaring a module).
private(module) and private(file) are relatively long, but the longest – private(module) – is rarely used (outside the standard library) as it's the default. Most uses of the old private are more appropriately done using the new private, so private(file) would likely be used less than private.
The scheme expands very well to named submodules, e.g. if you have a submodule named model you might limit the scope using private(model).
private(file) as opposed to private-file or private/file makes it more consistent with the new function-like syntax for e.g. attributes.

On Wed, Mar 16, 2016 at 11:26 AM, Ross O'Brien via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
It's occurring to me, reading these recent posts, that we have two orthogonal systems of access levels.

Swift's current access system is file based; a project file decides which files comprise a module, and the terms 'public', 'internal' and 'private' determine whether a property is accessible to all, accessible only within files of the module, or accessible only within a file. (This takes on an extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed concepts in this discussion, ask instead for a type-based access system similar to those in other languages including Objective-C, where 'public', 'protected' and 'private' are the terms of choice and they restrict access to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in the file-based access system and 'private' to a concept in the type-based access system.

I would prefer clearer terms which actually mention the restrictions of the level. For example, 'inherited', not 'protected', in the case of properties accessible by a class and its subclasses; 'declaration', rather than 'private' or 'scoped', to refer to properties only accessible within a given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I think this most-restricted level has managed to pass as a level of the file-based access system. However, if the system is ever extended, we're going to run into new syntax decisions where we have 'private module' functions (accessible only within the given type in the same module) trying to communicate with 'protected file' properties (accessible only with the type and its subtypes in the same file), and that might lead to conflicts, so perhaps we should decide how those might be declared now.

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom getter/setter implementations. We should definitely be able to do:

var foo:Int {
  public get {…}
  private(file) set {…}
}

In fact, that is what I first tried to do before learning about private(set). But without the implementations, it just seems strange to put the scoping after the rest of the declaration (they work above because they are before the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter, that might work too. I don’t love it, but maybe with better wording?

var foo:Int{
  public get useDefault
  private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel <patrickpijnappel@gmail.com <mailto:patrickpijnappel@gmail.com>> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel <patrickpijnappel@gmail.com <mailto:patrickpijnappel@gmail.com>> wrote:
I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets too inconsistent with private(set: public) and private(set: private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current “private(set)"
private(get: module, set: file) //getter has module scope & setter has file scope

It is a bit weird, but we should probably also allow “public" in that last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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

_______________________________________________
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
https://lists.swift.org/mailman/listinfo/swift-evolution


(Ilya Belenkiy) #11

The full form would then need to be private(scope). I think that
private(file, set) would be more consistent with private(set), which would
then be a shorthand for private(scope, set).

···

On Wed, Mar 16, 2016 at 4:18 AM Haravikk via swift-evolution < swift-evolution@swift.org> wrote:

I like the idea of repurposing brackets after private to do this. I think
though that it might be better if there were also a private(type) option to
allow us to be explicit about it, even if we can still type just private to
use it by default.

About replacing private(set), the examples you’ve given look like computed
properties, and being able to put the accessibility declaration before the
setter is a good option, but for stored properties I think we also need a
way to specify the restriction, for example private(file: set) to enable
setting the value only at the file level. This means that private on its
own is by default actually private(type: get set)

On 16 Mar 2016, at 06:49, Patrick Pijnappel via swift-evolution < > swift-evolution@swift.org> wrote:

Ok to summarize:

*Setter access modifiers*
var foo: Int { private set { ... } }
var foo: Int { private set }

   - Consistent with mutating set { ... }. Arguably the current
   private(set) is inconsistent.
   - Eliminates the odd corner case of having a double access modifier,
   e.g. public private(set) var foo: Int.
   - It's very sensible for custom getters/setters (top case), it just
   requires allowing a bodiless get/set. We already kinda do this in protocols.

*Access modifier keywords*
public/private(module)/private(file)/private

   - It's not clear from the keywords how restrictive
   local/private/internal are, while private(module) and private(file)
   are obvious. This makes a declaration either public, or private to a
   certain scope. Arguably e.g. public/module/file/declaration has
   similar benefits but they aren't as clearly access control related as a
   keyword (e.g. module could just as well be declaring a module).
   - private(module) and private(file) are relatively long, but the
   longest – private(module) – is rarely used (outside the standard
   library) as it's the default. Most uses of the old private are more
   appropriately done using the new private, so private(file) would
   likely be used less than private.
   - The scheme expands very well to named submodules, e.g. if you have a
   submodule named model you might limit the scope using private(model).
   - private(file) as opposed to private-file or private/file makes it
   more consistent with the new function-like syntax for e.g. attributes.

On Wed, Mar 16, 2016 at 11:26 AM, Ross O'Brien via swift-evolution < > swift-evolution@swift.org> wrote:

It's occurring to me, reading these recent posts, that we have two
orthogonal systems of access levels.

Swift's current access system is file based; a project file decides which
files comprise a module, and the terms 'public', 'internal' and 'private'
determine whether a property is accessible to all, accessible only within
files of the module, or accessible only within a file. (This takes on an
extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed
concepts in this discussion, ask instead for a type-based access system
similar to those in other languages including Objective-C, where 'public',
'protected' and 'private' are the terms of choice and they restrict access
to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in
the file-based access system and 'private' to a concept in the type-based
access system.

I would prefer clearer terms which actually mention the restrictions of
the level. For example, 'inherited', not 'protected', in the case of
properties accessible by a class and its subclasses; 'declaration', rather
than 'private' or 'scoped', to refer to properties only accessible within a
given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I
think this most-restricted level has managed to pass as a level of the
file-based access system. However, if the system is ever extended, we're
going to run into new syntax decisions where we have 'private module'
functions (accessible only within the given type in the same module) trying
to communicate with 'protected file' properties (accessible only with the
type and its subtypes in the same file), and that might lead to conflicts,
so perhaps we should decide how those might be declared now.

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution < >> swift-evolution@swift.org> wrote:

On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom
getter/setter implementations. We should definitely be able to do:

var foo:Int {
public get {…}
private(file) set {…}
}

In fact, that is what I first tried to do before learning about
private(set). But without the implementations, it just seems strange to
put the scoping after the rest of the declaration (they work above because
they are *before* the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax
for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter,
that might work too. I don’t love it, but maybe with better wording?

var foo:Int{
public get useDefault
private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel < >>> patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel < >>> patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just
gets too inconsistent with private(set: public) and private(set:
private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution < >>>> swift-evolution@swift.org> wrote:

*On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:*

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current
“private(set)"
private(get: module, set: file) //getter has module scope & setter has
file scope

It is a bit weird, but we should probably also allow “public" in that
last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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

_______________________________________________
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

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


(Ross O'Brien) #12

A question about parsing: one of the perceived disadvantages to 'module'
and 'file' is how easily they might also be used as variable names. How
easily the parser can tell from context whether they're intended as
variable names or as access level keywords is important to deciding whether
they're good choices for access level words, or whether they're better as
modifiers (e.g. 'private(module)' ). Is this a significant concern, or,
like argument labels in function calls, can the compiler handle this? (It
seems pretty likely to me that any accessibility label will be succeeded by
'class'/'enum'/'struct'/'protocol'/'let'/'var'/'func', but I don't know if
that's enough).

Also, returning to a point in Chris Lattner's original brief for this
discussion: how should this accessibility work with @testable?

At the moment, if a unit test file calls "import ModuleName" it has access
to a module's public symbols, but if it calls "@testable import ModuleName"
it has access to internal symbols. I like the idea of maintaining
"@testable" so it's clear which module is being tested regardless of access
level, but should we consider using the access level keywords as an
attribute to this in future?

e.g.
@testable(public) import ModuleName
@testable(internal) import ModuleName
@testable(file) import ModuleName // lets us test correctness of
file-scoped behaviours

If this is the case then this would seem clunky:
@testable(private(scope)) import ModuleName

···

On Wed, Mar 16, 2016 at 10:43 AM, Ilya Belenkiy via swift-evolution < swift-evolution@swift.org> wrote:

The full form would then need to be private(scope). I think that
private(file, set) would be more consistent with private(set), which would
then be a shorthand for private(scope, set).

On Wed, Mar 16, 2016 at 4:18 AM Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

I like the idea of repurposing brackets after private to do this. I think
though that it might be better if there were also a private(type) option to
allow us to be explicit about it, even if we can still type just private to
use it by default.

About replacing private(set), the examples you’ve given look like
computed properties, and being able to put the accessibility declaration
before the setter is a good option, but for stored properties I think we
also need a way to specify the restriction, for example private(file: set)
to enable setting the value only at the file level. This means that private
on its own is by default actually private(type: get set)

On 16 Mar 2016, at 06:49, Patrick Pijnappel via swift-evolution < >> swift-evolution@swift.org> wrote:

Ok to summarize:

*Setter access modifiers*
var foo: Int { private set { ... } }
var foo: Int { private set }

   - Consistent with mutating set { ... }. Arguably the current
   private(set) is inconsistent.
   - Eliminates the odd corner case of having a double access modifier,
   e.g. public private(set) var foo: Int.
   - It's very sensible for custom getters/setters (top case), it just
   requires allowing a bodiless get/set. We already kinda do this in protocols.

*Access modifier keywords*
public/private(module)/private(file)/private

   - It's not clear from the keywords how restrictive
   local/private/internal are, while private(module) and private(file)
   are obvious. This makes a declaration either public, or private to a
   certain scope. Arguably e.g. public/module/file/declaration has
   similar benefits but they aren't as clearly access control related as a
   keyword (e.g. module could just as well be declaring a module).
   - private(module) and private(file) are relatively long, but the
   longest – private(module) – is rarely used (outside the standard
   library) as it's the default. Most uses of the old private are more
   appropriately done using the new private, so private(file) would
   likely be used less than private.
   - The scheme expands very well to named submodules, e.g. if you have
   a submodule named model you might limit the scope using private(model)
   .
   - private(file) as opposed to private-file or private/file makes it
   more consistent with the new function-like syntax for e.g. attributes.

On Wed, Mar 16, 2016 at 11:26 AM, Ross O'Brien via swift-evolution < >> swift-evolution@swift.org> wrote:

It's occurring to me, reading these recent posts, that we have two
orthogonal systems of access levels.

Swift's current access system is file based; a project file decides
which files comprise a module, and the terms 'public', 'internal' and
'private' determine whether a property is accessible to all, accessible
only within files of the module, or accessible only within a file. (This
takes on an extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed
concepts in this discussion, ask instead for a type-based access system
similar to those in other languages including Objective-C, where 'public',
'protected' and 'private' are the terms of choice and they restrict access
to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in
the file-based access system and 'private' to a concept in the type-based
access system.

I would prefer clearer terms which actually mention the restrictions of
the level. For example, 'inherited', not 'protected', in the case of
properties accessible by a class and its subclasses; 'declaration', rather
than 'private' or 'scoped', to refer to properties only accessible within a
given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I
think this most-restricted level has managed to pass as a level of the
file-based access system. However, if the system is ever extended, we're
going to run into new syntax decisions where we have 'private module'
functions (accessible only within the given type in the same module) trying
to communicate with 'protected file' properties (accessible only with the
type and its subtypes in the same file), and that might lead to conflicts,
so perhaps we should decide how those might be declared now.

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution < >>> swift-evolution@swift.org> wrote:

On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:

And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom
getter/setter implementations. We should definitely be able to do:

var foo:Int {
public get {…}
private(file) set {…}
}

In fact, that is what I first tried to do before learning about
private(set). But without the implementations, it just seems strange to
put the scoping after the rest of the declaration (they work above because
they are *before* the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax
for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter,
that might work too. I don’t love it, but maybe with better wording?

var foo:Int{
public get useDefault
private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel < >>>> patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel < >>>> patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just
gets too inconsistent with private(set: public) and private(set:
private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution < >>>>> swift-evolution@swift.org> wrote:

*On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:*

The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current
“private(set)"
private(get: module, set: file) //getter has module scope & setter
has file scope

It is a bit weird, but we should probably also allow “public" in that
last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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

_______________________________________________
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

_______________________________________________
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


(Haravikk) #13

Does the parameter for @testable need to match exactly? An alternative could be to take it as @testable(private: scope), not quite as clunky but keeps the same basic structure of all restricted accessibility being “private” followed by a type of privacy.

I think that use of a modifier for private(scope) type declarations is the best way to go for avoiding introducing new keywords (actually it would free up internal). It’s actually a style that I’d like to see more of; there was discussion recently about introducing customisable property behaviours, but there was difficulty about how to apply them, however a behaviour(lazy) type syntax could solve that.

When it comes to parsing though, I think that it as long as let/var is required to be the last element before a property name then this eliminates most parsing issues regarding name collisions with properties.

···

On 16 Mar 2016, at 11:04, Ross O'Brien <narrativium+swift@gmail.com> wrote:

If this is the case then this would seem clunky:
@testable(private(scope)) import ModuleName


(Step C) #14

A question about parsing: one of the perceived disadvantages to 'module' and 'file' is how easily they might also be used as variable names. How easily the parser can tell from context whether they're intended as variable names or as access level keywords is important to deciding whether they're good choices for access level words, or whether they're better as modifiers (e.g. 'private(module)' ). Is this a significant concern, or, like argument labels in function calls, can the compiler handle this? (It seems pretty likely to me that any accessibility label will be succeeded by 'class'/'enum'/'struct'/'protocol'/'let'/'var'/'func', but I don't know if that's enough).

Also, returning to a point in Chris Lattner's original brief for this discussion: how should this accessibility work with @testable?

At the moment, if a unit test file calls "import ModuleName" it has access to a module's public symbols, but if it calls "@testable import ModuleName" it has access to internal symbols. I like the idea of maintaining "@testable" so it's clear which module is being tested regardless of access level, but should we consider using the access level keywords as an attribute to this in future?

e.g.
@testable(public) import ModuleName
@testable(internal) import ModuleName
@testable(file) import ModuleName // lets us test correctness of file-scoped behaviours

I like this idea, and want this capability. But my first thought is this would be better accomplished by a more fine-grained import capability. That is, the ability to import only certain parts from a module. Not sure that would handle the file case though.

···

On Mar 16, 2016, at 7:04 AM, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

If this is the case then this would seem clunky:
@testable(private(scope)) import ModuleName

On Wed, Mar 16, 2016 at 10:43 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:
The full form would then need to be private(scope). I think that private(file, set) would be more consistent with private(set), which would then be a shorthand for private(scope, set).

On Wed, Mar 16, 2016 at 4:18 AM Haravikk via swift-evolution <swift-evolution@swift.org> wrote:
I like the idea of repurposing brackets after private to do this. I think though that it might be better if there were also a private(type) option to allow us to be explicit about it, even if we can still type just private to use it by default.

About replacing private(set), the examples you’ve given look like computed properties, and being able to put the accessibility declaration before the setter is a good option, but for stored properties I think we also need a way to specify the restriction, for example private(file: set) to enable setting the value only at the file level. This means that private on its own is by default actually private(type: get set)

On 16 Mar 2016, at 06:49, Patrick Pijnappel via swift-evolution <swift-evolution@swift.org> wrote:

Ok to summarize:

Setter access modifiers
var foo: Int { private set { ... } }
var foo: Int { private set }
Consistent with mutating set { ... }. Arguably the current private(set) is inconsistent.
Eliminates the odd corner case of having a double access modifier, e.g. public private(set) var foo: Int.
It's very sensible for custom getters/setters (top case), it just requires allowing a bodiless get/set. We already kinda do this in protocols.

Access modifier keywords
public/private(module)/private(file)/private
It's not clear from the keywords how restrictive local/private/internal are, while private(module) and private(file) are obvious. This makes a declaration either public, or private to a certain scope. Arguably e.g. public/module/file/declaration has similar benefits but they aren't as clearly access control related as a keyword (e.g. module could just as well be declaring a module).
private(module) and private(file) are relatively long, but the longest – private(module) – is rarely used (outside the standard library) as it's the default. Most uses of the old private are more appropriately done using the new private, so private(file) would likely be used less than private.
The scheme expands very well to named submodules, e.g. if you have a submodule named model you might limit the scope using private(model).
private(file) as opposed to private-file or private/file makes it more consistent with the new function-like syntax for e.g. attributes.

On Wed, Mar 16, 2016 at 11:26 AM, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:
It's occurring to me, reading these recent posts, that we have two orthogonal systems of access levels.

Swift's current access system is file based; a project file decides which files comprise a module, and the terms 'public', 'internal' and 'private' determine whether a property is accessible to all, accessible only within files of the module, or accessible only within a file. (This takes on an extra dimension as files may belong to several modules).

The concept which began this discussion, and several of the proposed concepts in this discussion, ask instead for a type-based access system similar to those in other languages including Objective-C, where 'public', 'protected' and 'private' are the terms of choice and they restrict access to a type or subtypes.

I think it would be confusing if Swift applied 'public' to a concept in the file-based access system and 'private' to a concept in the type-based access system.

I would prefer clearer terms which actually mention the restrictions of the level. For example, 'inherited', not 'protected', in the case of properties accessible by a class and its subclasses; 'declaration', rather than 'private' or 'scoped', to refer to properties only accessible within a given type or extension declaration.

Since, at the moment, a declaration can only occur within one file, I think this most-restricted level has managed to pass as a level of the file-based access system. However, if the system is ever extended, we're going to run into new syntax decisions where we have 'private module' functions (accessible only within the given type in the same module) trying to communicate with 'protected file' properties (accessible only with the type and its subtypes in the same file), and that might lead to conflicts, so perhaps we should decide how those might be declared now.

On Tue, Mar 15, 2016 at 11:51 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote:

On Tue, Mar 15, 2016 at 2:33 PM Erica Sadun <erica at ericasadun.com> wrote:
And again, moving the access control modification to the end just doesn't look
right to me or seem to enhance readability. :frowning:

I like Shawn’s proposal better for cases where there are custom getter/setter implementations. We should definitely be able to do:

var foo:Int {
  public get {…}
  private(file) set {…}
}

In fact, that is what I first tried to do before learning about private(set). But without the implementations, it just seems strange to put the scoping after the rest of the declaration (they work above because they are before the custom getter/setter).

I still like the idea of having the option to use parameter-like syntax for cases where you don’t have custom getters/setters:

private var foo:Int
private(file) var foo:Int
private(set: file) var foo:Int
private(get: global, set: file) var foo:Int

I guess, if we had some way to represent the standard getter/setter, that might work too. I don’t love it, but maybe with better wording?

var foo:Int{
  public get useDefault
  private(file) set {…}
}

Thanks,
Jon

On Mar 14, 2016, at 10:22 PM, Patrick Pijnappel <patrickpijnappel@gmail.com> wrote:

I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

For example, we already use

var foo: Int { mutating get { ... } }

and not

mutating(get) var foo: Int { get { ... } }

On Tue, Mar 15, 2016 at 4:13 PM, Patrick Pijnappel <patrickpijnappel@gmail.com> wrote:
I like Shawn's proposal:

var foo: Int { private(file) set }

In fact it's probably more sensible than the current private(set) IMO.

While I like private(get: file, set: module) idea, I think it just gets too inconsistent with private(set: public) and private(set: private) (?!)

On Tue, Mar 15, 2016 at 3:39 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 8:36 PM, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org> wrote:
The only question is (as Sean mentioned) how this combines with the syntax
for setter access level, e.g. the current private(set). Options:
- Unnamed 2nd argument, giving private(file), private(file, set),
private(set).
- Named 2nd argument, giving e.g. private(file), private(file, accessor:
set), private(accessor: set). Less ambiguity but longer.
- Not using multiple arguments, but that'd probably break consistency with
the other unification efforts going on to make everything look like
function calls.

What about the following 3 forms?

private(file) //both setter and getter have file scope
private(set: file) //setter has file scope. Equivalent to current “private(set)"
private(get: module, set: file) //getter has module scope & setter has file scope

It is a bit weird, but we should probably also allow “public" in that last form: private(get: public, set: module)

Thanks,
Jon

_______________________________________________
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

_______________________________________________
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

_______________________________________________
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

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