Simplifying Access Using 'Hidden'


(Joanna Carter) #1

I would also say that access modifiers do seem to be be somewhat messy.

I have never liked the idea of fileprivate ; this is the equivalent of Delphi's private scope, to which they then added strict private for class only scope. That was a similar mess.

I am still not sure why we can't have the good old-fashioned visibilities of private, protected and public for classes. They have worked well for years and I feel we are changing things for change's sake.

For all types other than classes, where inheritance is a feature, we have private, internal and public.

For classes, we should definitely add protected ; I find internal just too exposing for stuff to be used exclusively by derived classes.

But, I believe one of the motives behind fileprivate was to satisfy the need for extensions to a type to access private members.

Just to put in my 2¬Ę worth, the only extra scope I would suggest could be named "extensible" and would allow anything so marked to be visible only as far as extensions ; the difference being that such extensions could then be placed in separate files.

So, private, protected (class only), internal, public and extensible.

Or is that too revolutionary ?

Joanna

···

Le 13/02/2017 à 15:15, Adrian Zubarev via swift-evolution a écrit :

‚Äď1

I won’t even try to be constructive on this one. It simply makes me
tired of all this access modifier mess. |open|, |closed|, |public|,
>internal>, now |hidden|, |fileprivate|, |directoryprivate|,
>moduleprivate>, |private|, I might even forget some of the proposed
access modifiers.

Instead of adding new stuff that explodes the complexity we should put
our energy and fix existing issues, like the inconsistent |open| for
example.


(Adrian Zubarev) #2

People talk always like ‚ÄúI never liked fileprivate‚ÄĚ and I feel like some of you forgot that fileprivate is not new to Swift. It‚Äôs the repainted private from days before Swift 3. I cannot recall anyone complaining about it that much. There were some people that forced the addition of a stricter private access modifier for Swift 3. Now that we have both, there are a lot of complains about fileprivate.

···

--
Adrian Zubarev
Sent with Airmail

Am 13. Februar 2017 um 17:10:45, Joanna Carter via swift-evolution (swift-evolution@swift.org) schrieb:

Le 13/02/2017 à 15:15, Adrian Zubarev via swift-evolution a écrit :

‚Äď1

I won’t even try to be constructive on this one. It simply makes me
tired of all this access modifier mess. |open|, |closed|, |public|,
>internal>, now |hidden|, |fileprivate|, |directoryprivate|,
>moduleprivate>, |private|, I might even forget some of the proposed
access modifiers.

Instead of adding new stuff that explodes the complexity we should put
our energy and fix existing issues, like the inconsistent |open| for
example.

I would also say that access modifiers do seem to be be somewhat messy.

I have never liked the idea of fileprivate ; this is the equivalent of Delphi's private scope, to which they then added strict private for class only scope. That was a similar mess.

I am still not sure why we can't have the good old-fashioned visibilities of private, protected and public for classes. They have worked well for years and I feel we are changing things for change's sake.

For all types other than classes, where inheritance is a feature, we have private, internal and public.

For classes, we should definitely add protected ; I find internal just too exposing for stuff to be used exclusively by derived classes.

But, I believe one of the motives behind fileprivate was to satisfy the need for extensions to a type to access private members.

Just to put in my 2¬Ę worth, the only extra scope I would suggest could be named "extensible" and would allow anything so marked to be visible only as far as extensions ; the difference being that such extensions could then be placed in separate files.

So, private, protected (class only), internal, public and extensible.

Or is that too revolutionary ?

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


(Dietmar Planitzer) #3

The problem with fileprivate is this: a new keyword was introduced for the original definition of private and a new definition of private was introduced that does not carry its weight in the context of Swift. Because of these two actions, the original definition of private was elevated to a level above the private keyword which by the end of the day is just a very weak version of a sub-module / package access level.

The original definition of private made sense in the context of Swift 2 because:

1) it fit into the definition of public and internal: private is everything inside a file, internal is everything inside a module and public is the subset of internal stuff that we want to be accessible outside the module boundary. This was a straight-forward conceptual model.

2) it played well together with the Swift definition of an extension and it provided some relieve to the limitation that an extension can’t define a private stored property: e.g. I was able to define a type inside of a file by splitting it up into a base type definition which would carry all the private stored properties and a series of extensions which would define the semantics of the type, organized into logical blocks.

Now in Swift 3 I have to use fileprivate to pull off (2) and fileprivate adds extra complexity to (1) without given me the flexibility to:

a) add support for sub-modules. Sub-modules would require the addition of yet another access level.

b) put the implementation of separate but strongly related types into separate files. Eg in order to implement a module which has a set of SPI

What worries me is that I see more and more proposals that want to add yet another bunch of access levels and I also see the sub-module discussion come up from time to time. It also worries me that Swift already has more access levels than e.g. Java, yet it is Java that allows me to more precisely express my intent because:

I) I can express the intent that this function / type X is only relevant inside this package Y and nobody outside the package should be able to access X

II) I can express the intent that this function X should only be accessed by a subclass A of B, but not outside the subclassing context

I feel that the Swift access level story, as it stands today, is not only needless complicated compared to other languages while actually providing less relevant expressivity, it also feels like that the complexity of this story will sharply increase over time while still not providing much more relevant expressivity.

So IMO Swift should:

1) go back to public, internal and private with the respective definitions of Swift 2 (yes, open is another useless addition to the access level story but I frankly see less chance of getting rid of that compared to fileprivate)

2) then figure out whether and how to add sub-module capabilities. Add a module access level in this case and consider removing internal (with an alias internal == module as a back combat step)

3) then, and only then, consider adding additional levels if there is a clearly measurable advantage in doing so

Regards,

Dietmar Planitzer

···

On Feb 13, 2017, at 08:21, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

People talk always like ‚ÄúI never liked fileprivate‚ÄĚ and I feel like some of you forgot that fileprivate is not new to Swift. It‚Äôs the repainted private from days before Swift 3. I cannot recall anyone complaining about it that much. There were some people that forced the addition of a stricter private access modifier for Swift 3. Now that we have both, there are a lot of complains about fileprivate.

--
Adrian Zubarev
Sent with Airmail

Am 13. Februar 2017 um 17:10:45, Joanna Carter via swift-evolution (swift-evolution@swift.org) schrieb:

Le 13/02/2017 à 15:15, Adrian Zubarev via swift-evolution a écrit :

> ‚Äď1
>
> I won’t even try to be constructive on this one. It simply makes me
> tired of all this access modifier mess. |open|, |closed|, |public|,
> >internal>, now |hidden|, |fileprivate|, |directoryprivate|,
> >moduleprivate>, |private|, I might even forget some of the proposed
> access modifiers.
>
> Instead of adding new stuff that explodes the complexity we should put
> our energy and fix existing issues, like the inconsistent |open| for
> example.

I would also say that access modifiers do seem to be be somewhat messy.

I have never liked the idea of fileprivate ; this is the equivalent of Delphi's private scope, to which they then added strict private for class only scope. That was a similar mess.

I am still not sure why we can't have the good old-fashioned visibilities of private, protected and public for classes. They have worked well for years and I feel we are changing things for change's sake.

For all types other than classes, where inheritance is a feature, we have private, internal and public.

For classes, we should definitely add protected ; I find internal just too exposing for stuff to be used exclusively by derived classes.

But, I believe one of the motives behind fileprivate was to satisfy the need for extensions to a type to access private members.

Just to put in my 2¬Ę worth, the only extra scope I would suggest could be named "extensible" and would allow anything so marked to be visible only as far as extensions ; the difference being that such extensions could then be placed in separate files.

So, private, protected (class only), internal, public and extensible.

Or is that too revolutionary ?

Joanna
_______________________________________________
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


(Karl) #4

It _is_ kind of ugly. I would support rearranging our access lives like this, with a parameterised ‚Äúprivate‚ÄĚ:

open
public
private(module) // today‚Äôs ‚Äúinternal‚ÄĚ
private(file) // today‚Äôs ‚Äúfileprivate‚ÄĚ
private // today‚Äôs ‚Äúprivate‚ÄĚ

It also opens the door to more nuanced access levels, such as private(type) to allow access to the hidden member in cross-file extensions but not generally throughout the module.

For properties, it would mean

public internal(set) var something: Bool

would become

public private(module, set) var something: Bool

at which point it might be nicer to flip the arguments and call it ‚Äúsetter‚ÄĚ:

public private(setter, module) var something: Bool

- Karl

···

On 13 Feb 2017, at 17:21, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

People talk always like ‚ÄúI never liked fileprivate‚ÄĚ and I feel like some of you forgot that fileprivate is not new to Swift. It‚Äôs the repainted private from days before Swift 3. I cannot recall anyone complaining about it that much. There were some people that forced the addition of a stricter private access modifier for Swift 3. Now that we have both, there are a lot of complains about fileprivate.


(Joanna Carter) #5

What still strikes me as odd is that we now seem to have a plethora of visibilities, some of which do not provide for a given context, some of which seem to be looking for a context to justify their existence.

Whatever it is called, I find the idea of a file scope visibility somewhat bizarre and at odds with the principle of standard OO class encapsulation.

The two main reasons I can see for the perceived need for fileprivate are :

1. being able to separate out "sections" of a class into various extensions

2. giving global junkies the ability to write all their code in one unit

Surely, there are members of a type that the writer wants to remain private, even if an extension were declared in the same file. Fine, we have private for that and, even if the writer declares members to be fileprivate, there is no way that any extension declared outside of the file can see those members.

Now, I have a problem with that. If I want to access non-public members when I extend a type, either I declare those extensions in the same unit and declare those members as fileprivate, or if I want to declare those extensions in another file, I have to move up to the next suitable scope, which is internal.

But internal is too "open" because it allows, not only my chosen extensions to see those members but, also, any other code in the entire module.

Having made use of the "friend" concept in C++, this "all or next to nothing" approach to visibility seems to leave me in much the same place as Objective-C, where I could only have private or public, unless I did some tricky stuff with class extensions, something which really didn't look that pretty.

There are some parts of a type that I would want to remain really, really private to the type, not even visible to an extension.

There are other parts of a type that I would want to be private to that type but also visible in, but only in, extensions explicitly written against that type.

Which is why I am suggesting the "extensible" scope : private to the declaring type but also and only visible within any extension to that type.

Here follows a highly contrived example :

// Person.swift
public struct Person
{
  public var name: String
  
  public extensible(set) var dateOfBirth: Date
  
  public var age: Int
  {
    // return calculated age as of today
  }

  init(name: String, dateOfBirth: Date)
  {
    self.name = name
    
    self.dateOfBirth = dateOfBirth // accessible as if it were private
}

// Registrar.swift
extension Person
{
  func correct(dateOfBirth: Date)
  {
    self.dateOfBirth = …
  }
}

// Test.swift
{
  let person = Person()
  
  person.dateOfBirth = … // compilation error, not visible
}

IMHO, this then removes one use case for fileprivate in that it allows privileged visibility to private members of a type in extensions, both in the same file and in any other file. But, it also ensures that not other code is allowed access, whether that be in non-extension code in the same file or other non-extension code anywhere else.

As for case 2. for fileprivate, if a developer wants to put all sorts of globals and other code in one file, then I doubt if they are even going to bother to use fileprivate, especially when they get internal visibility with less typing :wink:

Now, if someone could help me prepare this as a proposal…

···

--
Joanna Carter
Carter Consulting


(Jon Hull) #6

I think you hit the nail on the head in that the main issue is that our access control is mixing together several concepts (file-based, type-based, module-based, ‚Äúopen‚ÄĚ).

I don‚Äôt think anyone is actually reading the proposal though. Hidden is file based (not type based). It provides the functionality of protected, but using swift‚Äôs file based approach. The reason ‚Äėfileprivate‚Äô goes away is not because it isn‚Äôt possible, but because it is essentially redundant (with the shorter keyword of ‚Äėhidden‚Äô).

The big difference is that you can put extensions in separate files within the module (while still expressing intent). Which based on your assertion that "it's not particularly useful for the compiler to hide something from you that you can plainly see and touch‚ÄĚ is a good thing.

Also note that my proposal is completely compatible with either the Swift 2 or Swift 3 version of private. It does need one of them to stay, but either would work fine. As you say, having several shades of private is not helpful.

Without something like this, we are going to continue to see a proliferation of new levels/proposals (e.g. friend & protected), each with associated bookkeeping/boilerplate. The idea is to head that off and provide a single concept with enough flexibility to avoid that while still using Swift’s file based approach.

Thanks,
Jon

···

On Feb 13, 2017, at 3:38 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

The beauty of Swift 2's access modifiers was that they were based around files and modules, explicitly rejecting types and scopes as units for determining visibility. It seems at base there's a group of people who reject that decision altogether. Hence, new `private`, proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

The point of the other thread was that a sizable proportion of people are finding the old system to be elegant and a suitable basis for future enhancements such as submodules. Here, there's another proportion of people who want to dismantle the old design completely. This was pitched already during the Swift 3 evolution process, repeatedly.

At some point, we've got to stop relitigating this design. It's untenable to have something as foundational as access control change with every version of Swift.

My two cents are that supporting all the shades of private is completely a non-goal. I've yet to be convinced that more access modifiers will improve anyone's code sufficiently to justify any more turmoil in the language. The Swift 2 way took a very pragmatic approach. When can I access this member? If private: when I have the source code already open; if internal: when I have the source code available to open; if public: whenever. It takes the opinionated (but IMO correct) view that it's not particularly useful for the compiler to hide something from you that you can plainly see and touch.

On Mon, Feb 13, 2017 at 5:04 PM, Joanna Carter via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
What still strikes me as odd is that we now seem to have a plethora of visibilities, some of which do not provide for a given context, some of which seem to be looking for a context to justify their existence.

Whatever it is called, I find the idea of a file scope visibility somewhat bizarre and at odds with the principle of standard OO class encapsulation.

The two main reasons I can see for the perceived need for fileprivate are :

1. being able to separate out "sections" of a class into various extensions

2. giving global junkies the ability to write all their code in one unit

Surely, there are members of a type that the writer wants to remain private, even if an extension were declared in the same file. Fine, we have private for that and, even if the writer declares members to be fileprivate, there is no way that any extension declared outside of the file can see those members.

Now, I have a problem with that. If I want to access non-public members when I extend a type, either I declare those extensions in the same unit and declare those members as fileprivate, or if I want to declare those extensions in another file, I have to move up to the next suitable scope, which is internal.

But internal is too "open" because it allows, not only my chosen extensions to see those members but, also, any other code in the entire module.

Having made use of the "friend" concept in C++, this "all or next to nothing" approach to visibility seems to leave me in much the same place as Objective-C, where I could only have private or public, unless I did some tricky stuff with class extensions, something which really didn't look that pretty.

There are some parts of a type that I would want to remain really, really private to the type, not even visible to an extension.

There are other parts of a type that I would want to be private to that type but also visible in, but only in, extensions explicitly written against that type.

Which is why I am suggesting the "extensible" scope : private to the declaring type but also and only visible within any extension to that type.

Here follows a highly contrived example :

// Person.swift
public struct Person
{
  public var name: String

  public extensible(set) var dateOfBirth: Date

  public var age: Int
  {
    // return calculated age as of today
  }

  init(name: String, dateOfBirth: Date)
  {
    self.name <http://self.name/> = name

    self.dateOfBirth = dateOfBirth // accessible as if it were private
}

// Registrar.swift
extension Person
{
  func correct(dateOfBirth: Date)
  {
    self.dateOfBirth = …
  }
}

// Test.swift
{
  let person = Person()

  person.dateOfBirth = … // compilation error, not visible
}

IMHO, this then removes one use case for fileprivate in that it allows privileged visibility to private members of a type in extensions, both in the same file and in any other file. But, it also ensures that not other code is allowed access, whether that be in non-extension code in the same file or other non-extension code anywhere else.

As for case 2. for fileprivate, if a developer wants to put all sorts of globals and other code in one file, then I doubt if they are even going to bother to use fileprivate, especially when they get internal visibility with less typing :wink:

Now, if someone could help me prepare this as a proposal…

--
Joanna Carter
Carter Consulting

_______________________________________________
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


(Xiaodi Wu) #7

The beauty of Swift 2's access modifiers was that they were based around
files and modules, explicitly rejecting types and scopes as units for
determining visibility. It seems at base there's a group of people who
reject that decision altogether. Hence, new `private`, proposals around
`protected`, `friend`, `hidden`, `extensible`, etc.

The point of the other thread was that a sizable proportion of people are
finding the old system to be elegant and a suitable basis for future
enhancements such as submodules. Here, there's another proportion of people
who want to dismantle the old design completely. This was pitched already
during the Swift 3 evolution process, repeatedly.

At some point, we've got to stop relitigating this design. It's untenable
to have something as foundational as access control change with every
version of Swift.

My two cents are that supporting all the shades of private is completely a
non-goal. I've yet to be convinced that more access modifiers will improve
anyone's code sufficiently to justify any more turmoil in the language. The
Swift 2 way took a very pragmatic approach. When can I access this member?
If private: when I have the source code already open; if internal: when I
have the source code available to open; if public: whenever. It takes the
opinionated (but IMO correct) view that it's not particularly useful for
the compiler to hide something from you that you can plainly see and touch.

···

On Mon, Feb 13, 2017 at 5:04 PM, Joanna Carter via swift-evolution < swift-evolution@swift.org> wrote:

What still strikes me as odd is that we now seem to have a plethora of
visibilities, some of which do not provide for a given context, some of
which seem to be looking for a context to justify their existence.

Whatever it is called, I find the idea of a file scope visibility somewhat
bizarre and at odds with the principle of standard OO class encapsulation.

The two main reasons I can see for the perceived need for fileprivate are :

1. being able to separate out "sections" of a class into various extensions

2. giving global junkies the ability to write all their code in one unit

Surely, there are members of a type that the writer wants to remain
private, even if an extension were declared in the same file. Fine, we have
private for that and, even if the writer declares members to be
fileprivate, there is no way that any extension declared outside of the
file can see those members.

Now, I have a problem with that. If I want to access non-public members
when I extend a type, either I declare those extensions in the same unit
and declare those members as fileprivate, or if I want to declare those
extensions in another file, I have to move up to the next suitable scope,
which is internal.

But internal is too "open" because it allows, not only my chosen
extensions to see those members but, also, any other code in the entire
module.

Having made use of the "friend" concept in C++, this "all or next to
nothing" approach to visibility seems to leave me in much the same place as
Objective-C, where I could only have private or public, unless I did some
tricky stuff with class extensions, something which really didn't look that
pretty.

There are some parts of a type that I would want to remain really, really
private to the type, not even visible to an extension.

There are other parts of a type that I would want to be private to that
type but also visible in, but only in, extensions explicitly written
against that type.

Which is why I am suggesting the "extensible" scope : private to the
declaring type but also and only visible within any extension to that type.

Here follows a highly contrived example :

// Person.swift
public struct Person
{
  public var name: String

  public extensible(set) var dateOfBirth: Date

  public var age: Int
  {
    // return calculated age as of today
  }

  init(name: String, dateOfBirth: Date)
  {
    self.name = name

    self.dateOfBirth = dateOfBirth // accessible as if it were private
}

// Registrar.swift
extension Person
{
  func correct(dateOfBirth: Date)
  {
    self.dateOfBirth = …
  }
}

// Test.swift
{
  let person = Person()

  person.dateOfBirth = … // compilation error, not visible
}

IMHO, this then removes one use case for fileprivate in that it allows
privileged visibility to private members of a type in extensions, both in
the same file and in any other file. But, it also ensures that not other
code is allowed access, whether that be in non-extension code in the same
file or other non-extension code anywhere else.

As for case 2. for fileprivate, if a developer wants to put all sorts of
globals and other code in one file, then I doubt if they are even going to
bother to use fileprivate, especially when they get internal visibility
with less typing :wink:

Now, if someone could help me prepare this as a proposal…

--
Joanna Carter
Carter Consulting

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


(Adrian Zubarev) #8

I’ve never said, I liked the keyword by its name, however I do like its behavior which opens up flexible ways of creating some code dependency across the file. What I really meant is, that I feel like some people talk about fileprivate behavior as if it was new, which it is not.

I’m feeling with you about private(file), but I’m not sure about private(module), because internal is shorter and seems fine to me. :wink:

···

--
Adrian Zubarev
Sent with Airmail

Am 13. Februar 2017 um 17:35:42, Karl Wagner (razielim@gmail.com) schrieb:

On 13 Feb 2017, at 17:21, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

People talk always like ‚ÄúI never liked fileprivate‚ÄĚ and I feel like some of you forgot that fileprivate is not new to Swift. It‚Äôs the repainted private from days before Swift 3. I cannot recall anyone complaining about it that much. There were some people that forced the addition of a stricter private access modifier for Swift 3. Now that we have both, there are a lot of complains about fileprivate.

It _is_ kind of ugly. I would support rearranging our access lives like this, with a parameterised ‚Äúprivate‚ÄĚ:

open
public
private(module) // today‚Äôs ‚Äúinternal‚ÄĚ
private(file) // today‚Äôs ‚Äúfileprivate‚ÄĚ
private // today‚Äôs ‚Äúprivate‚ÄĚ

It also opens the door to more nuanced access levels, such as private(type) to allow access to the hidden member in cross-file extensions but not generally throughout the module.

For properties, it would mean

public internal(set) var something: Bool

would become

public private(module, set) var something: Bool

at which point it might be nicer to flip the arguments and call it ‚Äúsetter‚ÄĚ:

public private(setter, module) var something: Bool

- Karl


(Goffredo Marocchi) #9

A battle shout of "you will need language lawyers to decide all we are building to avoid protected" ;)?

···

Sent from my iPhone

On 13 Feb 2017, at 23:38, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

The beauty of Swift 2's access modifiers was that they were based around files and modules, explicitly rejecting types and scopes as units for determining visibility. It seems at base there's a group of people who reject that decision altogether. Hence, new `private`, proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

The point of the other thread was that a sizable proportion of people are finding the old system to be elegant and a suitable basis for future enhancements such as submodules. Here, there's another proportion of people who want to dismantle the old design completely. This was pitched already during the Swift 3 evolution process, repeatedly.

At some point, we've got to stop relitigating this design. It's untenable to have something as foundational as access control change with every version of Swift.

My two cents are that supporting all the shades of private is completely a non-goal. I've yet to be convinced that more access modifiers will improve anyone's code sufficiently to justify any more turmoil in the language. The Swift 2 way took a very pragmatic approach. When can I access this member? If private: when I have the source code already open; if internal: when I have the source code available to open; if public: whenever. It takes the opinionated (but IMO correct) view that it's not particularly useful for the compiler to hide something from you that you can plainly see and touch.

On Mon, Feb 13, 2017 at 5:04 PM, Joanna Carter via swift-evolution <swift-evolution@swift.org> wrote:
What still strikes me as odd is that we now seem to have a plethora of visibilities, some of which do not provide for a given context, some of which seem to be looking for a context to justify their existence.

Whatever it is called, I find the idea of a file scope visibility somewhat bizarre and at odds with the principle of standard OO class encapsulation.

The two main reasons I can see for the perceived need for fileprivate are :

1. being able to separate out "sections" of a class into various extensions

2. giving global junkies the ability to write all their code in one unit

Surely, there are members of a type that the writer wants to remain private, even if an extension were declared in the same file. Fine, we have private for that and, even if the writer declares members to be fileprivate, there is no way that any extension declared outside of the file can see those members.

Now, I have a problem with that. If I want to access non-public members when I extend a type, either I declare those extensions in the same unit and declare those members as fileprivate, or if I want to declare those extensions in another file, I have to move up to the next suitable scope, which is internal.

But internal is too "open" because it allows, not only my chosen extensions to see those members but, also, any other code in the entire module.

Having made use of the "friend" concept in C++, this "all or next to nothing" approach to visibility seems to leave me in much the same place as Objective-C, where I could only have private or public, unless I did some tricky stuff with class extensions, something which really didn't look that pretty.

There are some parts of a type that I would want to remain really, really private to the type, not even visible to an extension.

There are other parts of a type that I would want to be private to that type but also visible in, but only in, extensions explicitly written against that type.

Which is why I am suggesting the "extensible" scope : private to the declaring type but also and only visible within any extension to that type.

Here follows a highly contrived example :

// Person.swift
public struct Person
{
  public var name: String

  public extensible(set) var dateOfBirth: Date

  public var age: Int
  {
    // return calculated age as of today
  }

  init(name: String, dateOfBirth: Date)
  {
    self.name = name

    self.dateOfBirth = dateOfBirth // accessible as if it were private
}

// Registrar.swift
extension Person
{
  func correct(dateOfBirth: Date)
  {
    self.dateOfBirth = …
  }
}

// Test.swift
{
  let person = Person()

  person.dateOfBirth = … // compilation error, not visible
}

IMHO, this then removes one use case for fileprivate in that it allows privileged visibility to private members of a type in extensions, both in the same file and in any other file. But, it also ensures that not other code is allowed access, whether that be in non-extension code in the same file or other non-extension code anywhere else.

As for case 2. for fileprivate, if a developer wants to put all sorts of globals and other code in one file, then I doubt if they are even going to bother to use fileprivate, especially when they get internal visibility with less typing :wink:

Now, if someone could help me prepare this as a proposal…

--
Joanna Carter
Carter Consulting

_______________________________________________
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


(Joanna Carter) #10

The beauty of Swift 2's access modifiers was that they were based around files and modules, explicitly rejecting types and scopes as units for determining visibility. It seems at base there's a group of people who reject that decision altogether. Hence, new `private`, proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

I suppose, for those coming from an Objective-C only background, any extra visibilities are seen as a bonus.

For those coming from a Pascal background, file-based visibility seems more natural.

But for those of us who have used languages like C++ and C#, losing the visibilities that we have been used to can seriously affect how we think and design stuff.

FMPOV, it would seem that one of the "features" of Swift is a much more protocol and struct approach to design. Instead of using class inheritance to add functionality to an entity, we are encouraged to use extensions.

But, in so doing, those of us who are used to inheritance find that we can no longer limit visibility to a "hierarchy" but, instead, when we want to extend a type whilst accessing "privileged" members, we either have to put all our extensions in the same file as the base type, or raise the visibility of those privileged members to internal scope, thus allowing code anywhere in the same module to access and/or mutate it.

I have read https://developer.apple.com/swift/blog/?id=11 and I can see the reasoning against protected explained there but…

Once again, I see the "it was good enough for Objective-C" reasoning being a strong driver here but, this is Swift, where things can be done differently/better.

Allowing internal scope visibility is less of a problem when you are the only one writing the module and know intimately the intent and purpose of everything but when working in a team environment, it is all too easy for another developer to start "interfering" with your carefully designed logic by using it in ways that you had not anticipated.

I can understand the reasoning behind not using the concept of protected visibility but still feel that there are times when restricting visibility only to extending entities, whether that be subclasses of a class or extensions of any type, including structs and enums.

I would also like to argue that the use of open vs public for classes is quite confusing when we already have the option of marking a class or its members as final ; which seems to do much the same as leaving a class as public.

Except open is not truly a restriction of visibility, it is more a restriction on inheritance.

To quote the above blog, "In contrast, protected conflates access with inheritance". Surely "open" also conflates access with inheritance? It affects, not what external code can see but how the inheritance chain is controlled, as does final. In fact, I would dare to say that the difference between open/public and final is possibly too fine to be of sufficient importance to justify the existence of both ; or, at least, it is sufficiently confusing to encourage newer developers to throw their hands up in despair and simply leave everything as internal or public until they stumble across a compilation error.

The only real difference I can make out between open/public and final is that, once again, open/public is more module-based, whereas final is class based.

Why, when we are allowed final as a class only modifier, can't we have protected as a class only visibility?

Or, as I have mentioned previously, should we have a much more "Swifty" version of protected that allows more concisely defined visibility, not only within class hierarchies, but also within the full range of Swift "hierarchies", otherwise known as extensions?

My suggestion of "extensible" is intended to replace the perceived need for "protected" for classes, whilst unifying that concept of privileged access within a class hierarchy, with a similar, and increasingly demanded, privileged access for extensions of all types.

To elucidate further :

Before Swift, if we wanted a hierarchy of types, all with common base behaviour, without having to write the same code in every type, we were limited to using classes with their visibilities of private, protected and public.

Now Swift encourages us to declare protocols, which can have extensions that can define base behaviour, as long as that behaviour doesn't include stored data. We can then "inherit" that behaviour either in classes, structs or enums that implement the "base" protocol.

So, an interesting question is : should we look at getting rid of class inheritance altogether in favour of "protocol-based inheritance"?

Oh, and finally for this post, can anyone please tell me exactly what fileprivate brings to the table?

To my mind, although it allows access to private members of another type, it also requires that any type, wishing to take advantage of that privilege, has to be declared in the same file ; so, sort of like protected visibility but on a file basis.

But what if I have a relatively small abstract type (protocol or class) that is the basis of a larger "hierarchy"? Using fileprivate in the base type would mean that I would have to declare my whole hierarchy within that one file instead of placing each "subtype" or "implementing type" in their own files.

What happened to the "types should only be one screenful" school of thinking? :slight_smile:

···

--
Joanna Carter
Carter Consulting


(Vladimir) #11

Was surprised that you expressed exactly what I'm thinking about this subject.

I do believe even in Swift we need a way to say "only code that *knows* what it does should see this" and to not force us to write(and manage) the the code in same file.
Yes, some implementation details that shouldn't be used by "users" of the type, but can be used by "extenders" of our type. At least in the same module.

While reading, the question was raised(if was discussed, let me know pls): what if we extend the meaning of 'private' to 'visible to current type/scope and subtypes and extensions in the *same module*' ?
This will help us to split types by files, help to better model access policy for fields/methods(i.e. only scope that can know about details can see them) while 'private' still will be hidden outside of the module even for subclasses/extensions.

So, we'll have such situation:

"modifier" -> "can be accessed from"

···

On 15.02.2017 14:29, Joanna Carter via swift-evolution wrote:

The beauty of Swift 2's access modifiers was that they were based
around files and modules, explicitly rejecting types and scopes as
units for determining visibility. It seems at base there's a group of
people who reject that decision altogether. Hence, new `private`,
proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

I suppose, for those coming from an Objective-C only background, any
extra visibilities are seen as a bonus.

For those coming from a Pascal background, file-based visibility seems
more natural.

But for those of us who have used languages like C++ and C#, losing the
visibilities that we have been used to can seriously affect how we think
and design stuff.

-------------------------------
public -> outside of the mondule
internal -> inside the module only
fileprivate -> the same file only
private -> the same type/scope, or subtype, or extension in the same module. I.e. some kind of 'internal' but scope-oriented.

Actually I still believe we need current 'private' and additionally some 'protected' with meaning "access from subtype, or extension" probably with this limitation: "only in the same module". But suggested extended 'private' will be also OK for me.

Thoughts?

Vladimir.

FMPOV, it would seem that one of the "features" of Swift is a much more
protocol and struct approach to design. Instead of using class
inheritance to add functionality to an entity, we are encouraged to use
extensions.

But, in so doing, those of us who are used to inheritance find that we
can no longer limit visibility to a "hierarchy" but, instead, when we
want to extend a type whilst accessing "privileged" members, we either
have to put all our extensions in the same file as the base type, or
raise the visibility of those privileged members to internal scope, thus
allowing code anywhere in the same module to access and/or mutate it.

I have read https://developer.apple.com/swift/blog/?id=11 and I can see
the reasoning against protected explained there but…

Once again, I see the "it was good enough for Objective-C" reasoning
being a strong driver here but, this is Swift, where things can be done
differently/better.

Allowing internal scope visibility is less of a problem when you are the
only one writing the module and know intimately the intent and purpose
of everything but when working in a team environment, it is all too easy
for another developer to start "interfering" with your carefully
designed logic by using it in ways that you had not anticipated.

I can understand the reasoning behind not using the concept of protected
visibility but still feel that there are times when restricting
visibility only to extending entities, whether that be subclasses of a
class or extensions of any type, including structs and enums.

I would also like to argue that the use of open vs public for classes is
quite confusing when we already have the option of marking a class or
its members as final ; which seems to do much the same as leaving a
class as public.

Except open is not truly a restriction of visibility, it is more a
restriction on inheritance.

To quote the above blog, "In contrast, protected conflates access with
inheritance". Surely "open" also conflates access with inheritance? It
affects, not what external code can see but how the inheritance chain is
controlled, as does final. In fact, I would dare to say that the
difference between open/public and final is possibly too fine to be of
sufficient importance to justify the existence of both ; or, at least,
it is sufficiently confusing to encourage newer developers to throw
their hands up in despair and simply leave everything as internal or
public until they stumble across a compilation error.

The only real difference I can make out between open/public and final is
that, once again, open/public is more module-based, whereas final is
class based.

Why, when we are allowed final as a class only modifier, can't we have
protected as a class only visibility?

Or, as I have mentioned previously, should we have a much more "Swifty"
version of protected that allows more concisely defined visibility, not
only within class hierarchies, but also within the full range of Swift
"hierarchies", otherwise known as extensions?

My suggestion of "extensible" is intended to replace the perceived need
for "protected" for classes, whilst unifying that concept of privileged
access within a class hierarchy, with a similar, and increasingly
demanded, privileged access for extensions of all types.

To elucidate further :

Before Swift, if we wanted a hierarchy of types, all with common base
behaviour, without having to write the same code in every type, we were
limited to using classes with their visibilities of private, protected
and public.

Now Swift encourages us to declare protocols, which can have extensions
that can define base behaviour, as long as that behaviour doesn't
include stored data. We can then "inherit" that behaviour either in
classes, structs or enums that implement the "base" protocol.

So, an interesting question is : should we look at getting rid of class
inheritance altogether in favour of "protocol-based inheritance"?

Oh, and finally for this post, can anyone please tell me exactly what
fileprivate brings to the table?

To my mind, although it allows access to private members of another
type, it also requires that any type, wishing to take advantage of that
privilege, has to be declared in the same file ; so, sort of like
protected visibility but on a file basis.

But what if I have a relatively small abstract type (protocol or class)
that is the basis of a larger "hierarchy"? Using fileprivate in the base
type would mean that I would have to declare my whole hierarchy within
that one file instead of placing each "subtype" or "implementing type"
in their own files.

What happened to the "types should only be one screenful" school of
thinking? :slight_smile:

-- Joanna Carter Carter Consulting

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


(Matthew Johnson) #12

The beauty of Swift 2's access modifiers was that they were based
around files and modules, explicitly rejecting types and scopes as
units for determining visibility. It seems at base there's a group of
people who reject that decision altogether. Hence, new `private`,
proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

I suppose, for those coming from an Objective-C only background, any
extra visibilities are seen as a bonus.

For those coming from a Pascal background, file-based visibility seems
more natural.

But for those of us who have used languages like C++ and C#, losing the
visibilities that we have been used to can seriously affect how we think
and design stuff.

Was surprised that you expressed exactly what I'm thinking about this subject.

I do believe even in Swift we need a way to say "only code that *knows* what it does should see this" and to not force us to write(and manage) the the code in same file.
Yes, some implementation details that shouldn't be used by "users" of the type, but can be used by "extenders" of our type. At least in the same module.

While reading, the question was raised(if was discussed, let me know pls): what if we extend the meaning of 'private' to 'visible to current type/scope and subtypes and extensions in the *same module*' ?
This will help us to split types by files, help to better model access policy for fields/methods(i.e. only scope that can know about details can see them) while 'private' still will be hidden outside of the module even for subclasses/extensions.

So, we'll have such situation:

"modifier" -> "can be accessed from"
-------------------------------
public -> outside of the mondule
internal -> inside the module only
fileprivate -> the same file only
private -> the same type/scope, or subtype, or extension in the same module. I.e. some kind of 'internal' but scope-oriented.

Actually I still believe we need current 'private' and additionally some 'protected' with meaning "access from subtype, or extension" probably with this limitation: "only in the same module". But suggested extended 'private' will be also OK for me.

Thoughts?

Here's an idea in three points:

1. Return to the Swift 2 definition of `private`.
2. Introduce `scoped` to limit the visibility to within the same type, subtype, or extension.
3. Allow mixing the two.

So you have:

  private // current file
  private scoped // current file, in the same type, subtype, or ext.
  internal // current module
  internal scoped // current module, in the same type, subtype, or ext.
  public // external modules
  public scoped // maybe we want that one?

Since `internal` is implied, using `scoped` alone would be equivalent to `internal scoped`.

Swift 3's private could be mapped to `private scoped` to achieve (almost) the same results and thus preserve source compatibility.

This definition of `scoped` is actually much different than the current `private` which restricts visibility to the *current* scope. Your definition allows visibility in an unlimited number of scopes that just happen to be of the same type. I don’t think `scoped` is a good name for this.

`private(type)` would be a better name if we were going to make this a modification of the existing access modifiers. However, I don‚Äôt think this is the right direction. If we‚Äôre going to have an access modifier that means ‚Äúin the same file *and* the same type‚ÄĚ I think that should simply be called `private` (a ‚Äúsoft default‚ÄĚ). If we‚Äôre going to have something between `internal` and `fileprivate` I think it would be better to explore submodules than introduce something like `internal(type)`.

···

On Feb 15, 2017, at 9:37 AM, Michel Fortin via swift-evolution <swift-evolution@swift.org> wrote:

Le 15 févr. 2017 à 9:28, Vladimir.S via swift-evolution <swift-evolution@swift.org> a écrit :
On 15.02.2017 14:29, Joanna Carter via swift-evolution wrote:

--
Michel Fortin
https://michelf.ca

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


(Michel Fortin) #13

Here's an idea in three points:

1. Return to the Swift 2 definition of `private`.
2. Introduce `scoped` to limit the visibility to within the same type, subtype, or extension.
3. Allow mixing the two.

So you have:

  private // current file
  private scoped // current file, in the same type, subtype, or ext.
  internal // current module
  internal scoped // current module, in the same type, subtype, or ext.
  public // external modules
  public scoped // maybe we want that one?

Since `internal` is implied, using `scoped` alone would be equivalent to `internal scoped`.

Swift 3's private could be mapped to `private scoped` to achieve (almost) the same results and thus preserve source compatibility.

···

Le 15 févr. 2017 à 9:28, Vladimir.S via swift-evolution <swift-evolution@swift.org> a écrit :

On 15.02.2017 14:29, Joanna Carter via swift-evolution wrote:

The beauty of Swift 2's access modifiers was that they were based
around files and modules, explicitly rejecting types and scopes as
units for determining visibility. It seems at base there's a group of
people who reject that decision altogether. Hence, new `private`,
proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

I suppose, for those coming from an Objective-C only background, any
extra visibilities are seen as a bonus.

For those coming from a Pascal background, file-based visibility seems
more natural.

But for those of us who have used languages like C++ and C#, losing the
visibilities that we have been used to can seriously affect how we think
and design stuff.

Was surprised that you expressed exactly what I'm thinking about this subject.

I do believe even in Swift we need a way to say "only code that *knows* what it does should see this" and to not force us to write(and manage) the the code in same file.
Yes, some implementation details that shouldn't be used by "users" of the type, but can be used by "extenders" of our type. At least in the same module.

While reading, the question was raised(if was discussed, let me know pls): what if we extend the meaning of 'private' to 'visible to current type/scope and subtypes and extensions in the *same module*' ?
This will help us to split types by files, help to better model access policy for fields/methods(i.e. only scope that can know about details can see them) while 'private' still will be hidden outside of the module even for subclasses/extensions.

So, we'll have such situation:

"modifier" -> "can be accessed from"
-------------------------------
public -> outside of the mondule
internal -> inside the module only
fileprivate -> the same file only
private -> the same type/scope, or subtype, or extension in the same module. I.e. some kind of 'internal' but scope-oriented.

Actually I still believe we need current 'private' and additionally some 'protected' with meaning "access from subtype, or extension" probably with this limitation: "only in the same module". But suggested extended 'private' will be also OK for me.

Thoughts?

--
Michel Fortin
https://michelf.ca


(Michel Fortin) #14

I was using the definition of `private` from Vladimir.S's post quoted above because this is basically an extension of his idea. You're right that `scoped` might not be the best word for this.

···

Le 15 févr. 2017 à 10:52, Matthew Johnson <matthew@anandabits.com> a écrit :

On Feb 15, 2017, at 9:37 AM, Michel Fortin via swift-evolution <swift-evolution@swift.org> wrote:

Le 15 févr. 2017 à 9:28, Vladimir.S via swift-evolution <swift-evolution@swift.org> a écrit :

On 15.02.2017 14:29, Joanna Carter via swift-evolution wrote:

The beauty of Swift 2's access modifiers was that they were based
around files and modules, explicitly rejecting types and scopes as
units for determining visibility. It seems at base there's a group of
people who reject that decision altogether. Hence, new `private`,
proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

I suppose, for those coming from an Objective-C only background, any
extra visibilities are seen as a bonus.

For those coming from a Pascal background, file-based visibility seems
more natural.

But for those of us who have used languages like C++ and C#, losing the
visibilities that we have been used to can seriously affect how we think
and design stuff.

Was surprised that you expressed exactly what I'm thinking about this subject.

I do believe even in Swift we need a way to say "only code that *knows* what it does should see this" and to not force us to write(and manage) the the code in same file.
Yes, some implementation details that shouldn't be used by "users" of the type, but can be used by "extenders" of our type. At least in the same module.

While reading, the question was raised(if was discussed, let me know pls): what if we extend the meaning of 'private' to 'visible to current type/scope and subtypes and extensions in the *same module*' ?
This will help us to split types by files, help to better model access policy for fields/methods(i.e. only scope that can know about details can see them) while 'private' still will be hidden outside of the module even for subclasses/extensions.

So, we'll have such situation:

"modifier" -> "can be accessed from"
-------------------------------
public -> outside of the mondule
internal -> inside the module only
fileprivate -> the same file only
private -> the same type/scope, or subtype, or extension in the same module. I.e. some kind of 'internal' but scope-oriented.

Actually I still believe we need current 'private' and additionally some 'protected' with meaning "access from subtype, or extension" probably with this limitation: "only in the same module". But suggested extended 'private' will be also OK for me.

Thoughts?

Here's an idea in three points:

1. Return to the Swift 2 definition of `private`.
2. Introduce `scoped` to limit the visibility to within the same type, subtype, or extension.
3. Allow mixing the two.

So you have:

  private // current file
  private scoped // current file, in the same type, subtype, or ext.
  internal // current module
  internal scoped // current module, in the same type, subtype, or ext.
  public // external modules
  public scoped // maybe we want that one?

Since `internal` is implied, using `scoped` alone would be equivalent to `internal scoped`.

Swift 3's private could be mapped to `private scoped` to achieve (almost) the same results and thus preserve source compatibility.

This definition of `scoped` is actually much different than the current `private` which restricts visibility to the *current* scope. Your definition allows visibility in an unlimited number of scopes that just happen to be of the same type. I don’t think `scoped` is a good name for this.

--
Michel Fortin
https://michelf.ca


(Vladimir) #15

Inline

The beauty of Swift 2's access modifiers was that they were based
around files and modules, explicitly rejecting types and scopes as
units for determining visibility. It seems at base there's a group of
people who reject that decision altogether. Hence, new `private`,
proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

I suppose, for those coming from an Objective-C only background, any
extra visibilities are seen as a bonus.

For those coming from a Pascal background, file-based visibility seems
more natural.

But for those of us who have used languages like C++ and C#, losing the
visibilities that we have been used to can seriously affect how we think
and design stuff.

Was surprised that you expressed exactly what I'm thinking about this subject.

I do believe even in Swift we need a way to say "only code that *knows* what it does should see this" and to not force us to write(and manage) the the code in same file.
Yes, some implementation details that shouldn't be used by "users" of the type, but can be used by "extenders" of our type. At least in the same module.

While reading, the question was raised(if was discussed, let me know pls): what if we extend the meaning of 'private' to 'visible to current type/scope and subtypes and extensions in the *same module*' ?
This will help us to split types by files, help to better model access policy for fields/methods(i.e. only scope that can know about details can see them) while 'private' still will be hidden outside of the module even for subclasses/extensions.

So, we'll have such situation:

"modifier" -> "can be accessed from"
-------------------------------
public -> outside of the mondule
internal -> inside the module only
fileprivate -> the same file only
private -> the same type/scope, or subtype, or extension in the same module. I.e. some kind of 'internal' but scope-oriented.

Actually I still believe we need current 'private' and additionally some 'protected' with meaning "access from subtype, or extension" probably with this limitation: "only in the same module". But suggested extended 'private' will be also OK for me.

Thoughts?

Here's an idea in three points:

1. Return to the Swift 2 definition of `private`.
2. Introduce `scoped` to limit the visibility to within the same type, subtype, or extension.
3. Allow mixing the two.

So you have:

  private // current file
  private scoped // current file, in the same type, subtype, or ext.
  internal // current module
  internal scoped // current module, in the same type, subtype, or ext.
  public // external modules
  public scoped // maybe we want that one?

Since `internal` is implied, using `scoped` alone would be equivalent to `internal scoped`.

Swift 3's private could be mapped to `private scoped` to achieve (almost) the same results and thus preserve source compatibility.

Yes, I thought that we probably need the ability to specify "at any place in current file"(to work from "friend" types) and "in any subtype(?) and extension outside of the file". But I don't actually like the suggested composition of modifiers, too complicated as for me.

Well.. probably I would be happy with such schema:
public/open - as currently
internal - as currently
fileprivate - as currently
private - as currently + "in any subtype or extension in the same module"
protected(or other keyword) - as fileprivate + private, i.e."in this file and in any subtype/extension in other files, in the same module"

···

On 15.02.2017 18:37, Michel Fortin wrote:

Le 15 févr. 2017 à 9:28, Vladimir.S via swift-evolution <swift-evolution@swift.org> a écrit :
On 15.02.2017 14:29, Joanna Carter via swift-evolution wrote:


(Jean-Daniel) #16

Alternative plan:

1. Return to the Swift 2 definition of `private`.
2. Work on submodule.
3. Work on visibility.

As the visibility and the way the code is structures will be a major goal of submodule, I don’t think it is worth investing more time on Access visibility until we know more about submodules.

···

Le 15 févr. 2017 à 16:37, Michel Fortin via swift-evolution <swift-evolution@swift.org> a écrit :

Le 15 févr. 2017 à 9:28, Vladimir.S via swift-evolution <swift-evolution@swift.org> a écrit :

On 15.02.2017 14:29, Joanna Carter via swift-evolution wrote:

The beauty of Swift 2's access modifiers was that they were based
around files and modules, explicitly rejecting types and scopes as
units for determining visibility. It seems at base there's a group of
people who reject that decision altogether. Hence, new `private`,
proposals around `protected`, `friend`, `hidden`, `extensible`, etc.

I suppose, for those coming from an Objective-C only background, any
extra visibilities are seen as a bonus.

For those coming from a Pascal background, file-based visibility seems
more natural.

But for those of us who have used languages like C++ and C#, losing the
visibilities that we have been used to can seriously affect how we think
and design stuff.

Was surprised that you expressed exactly what I'm thinking about this subject.

I do believe even in Swift we need a way to say "only code that *knows* what it does should see this" and to not force us to write(and manage) the the code in same file.
Yes, some implementation details that shouldn't be used by "users" of the type, but can be used by "extenders" of our type. At least in the same module.

While reading, the question was raised(if was discussed, let me know pls): what if we extend the meaning of 'private' to 'visible to current type/scope and subtypes and extensions in the *same module*' ?
This will help us to split types by files, help to better model access policy for fields/methods(i.e. only scope that can know about details can see them) while 'private' still will be hidden outside of the module even for subclasses/extensions.

So, we'll have such situation:

"modifier" -> "can be accessed from"
-------------------------------
public -> outside of the mondule
internal -> inside the module only
fileprivate -> the same file only
private -> the same type/scope, or subtype, or extension in the same module. I.e. some kind of 'internal' but scope-oriented.

Actually I still believe we need current 'private' and additionally some 'protected' with meaning "access from subtype, or extension" probably with this limitation: "only in the same module". But suggested extended 'private' will be also OK for me.

Thoughts?

Here's an idea in three points:

1. Return to the Swift 2 definition of `private`.
2. Introduce `scoped` to limit the visibility to within the same type, subtype, or extension.
3. Allow mixing the two.


(Joanna Carter) #17

Was surprised that you expressed exactly what I'm thinking about this subject.

I do believe even in Swift we need a way to say "only code that *knows* what it does should see this" and to not force us to write(and manage) the the code in same file.
Yes, some implementation details that shouldn't be used by "users" of the type, but can be used by "extenders" of our type. At least in the same module.

Indeed. I spent a number of years designing and implementing a very large framework (in C#) for a company who had a small team of developers of varying skill levels and, whether they were working on the framework or on the app that used the framework, the number one consideration had to be ensuring that they were not able to break something that was already tested and approved, inadvertently, whilst working on another part of the project. this was especially relevant to work being done on classes that derived from base classes or classes that implemented interfaces (protocols).

With the present state of Swift, I would not be as confident handing out such tasks to a team using this language.

While reading, the question was raised(if was discussed, let me know pls): what if we extend the meaning of 'private' to 'visible to current type/scope and subtypes and extensions in the *same module*' ?
This will help us to split types by files, help to better model access policy for fields/methods(i.e. only scope that can know about details can see them) while 'private' still will be hidden outside of the module even for subclasses/extensions.

Hmm. I really don't like the idea of extending private to mean anything other than inside the declaring scope. I was one of those who was disappointed with the Swift 2 definition of it being file scope, having seen the abuse and generally bad code that developers fall into when allowed that freedom. In Delphi, I have seen some horrendously large files that contained everything but the kitchen sink ; when I asked the developer why he had done it, he said it was because, otherwise, he couldn't access the private members of a base class (he didn't understand the concept of protected visibility :sunglasses:

Actually I still believe we need current 'private' and additionally some 'protected' with meaning "access from subtype, or extension" probably with this limitation: "only in the same module". But suggested extended 'private' will be also OK for me.

And this is where I find myself. My suggestion was to try to integrate the idea of "protected" within class hierarchies with the need for privileged access for extensions to other types, whether they be in the same module or not.

Hence the name "extensible" to signify whether you were extending a class by inheritance or any other type with an extension, we would only need the one keyword to clearly express the concept.

···

--
Joanna Carter
Carter Consulting


(Joanna Carter) #18

Here's an idea in three points:

1. Return to the Swift 2 definition of `private`.
2. Introduce `scoped` to limit the visibility to within the same type, subtype, or extension.
3. Allow mixing the two.

So you have:

  private // current file
  private scoped // current file, in the same type, subtype, or ext.
  internal // current module
  internal scoped // current module, in the same type, subtype, or ext.
  public // external modules
  public scoped // maybe we want that one?

Since `internal` is implied, using `scoped` alone would be equivalent to `internal scoped`.

Swift 3's private could be mapped to `private scoped` to achieve (almost) the same results and thus preserve source compatibility.

Without wishing to offend, this seems to be creating a lot more keywords for people to try and get their heads around. I am a firm believer in KISS and would like to see the bare minimum of keywords for scopes, so as not to confuse the elderly, frail, young, inexperienced, etc :wink:

···

--
Joanna Carter
Carter Consulting


(Joanna Carter) #19

This definition of `scoped` is actually much different than the current `private` which restricts visibility to the *current* scope. Your definition allows visibility in an unlimited number of scopes that just happen to be of the same type. I don’t think `scoped` is a good name for this.

Agreed

`private(type)` would be a better name if we were going to make this a modification of the existing access modifiers. However, I don‚Äôt think this is the right direction. If we‚Äôre going to have an access modifier that means ‚Äúin the same file *and* the same type‚ÄĚ I think that should simply be called `private` (a ‚Äúsoft default‚ÄĚ). If we‚Äôre going to have something between `internal` and `fileprivate` I think it would be better to explore submodules than introduce something like `internal(type)`.

I remember discussions earlier in Swift's history about bracketed keywords and it is my opinion that, when you consider other such syntax, such as public private(set) var … , this could, all too soon, get very confusing.

···

--
Joanna Carter
Carter Consulting