access control

I don't understand your conception of encapsulation. The way you're putting it, because of Swift's access modifiers, encapsulation is relative to whether you have access to the original source or not.

It’s not *my* conception of encapsulation. There is only one: a class provides a public interface, and the internal state can be accessed only through that public interface. The only way to get to the private state is to modify the class itself. This is not the case with Swift — any code in the same file as the class can get access to the internal state and potentially break it.

The way you're putting it, because of Swift's access modifiers, encapsulation is relative to whether you have access to the original source or not. However, this is trivially true in any condition and whether Swift promoted a "private" or "local" access modifier would change nothing to it.

The difference is that with “local” you must change the class definition itself, and the change is very visible. With “private”, as long as the change is in the same file, the caller could accidentally (or deliberately) call an API that is meant to be private and break the object internal state.

In my opinion, this solution will be confusing to a lot of people

That may be only because of unfortunate names for these access modifiers. What is now called “private” should really be “file internal” or something like that. And “local” should be “private”. But that name is already taken. Another alternative is to do the automatic renaming, but I didn’t want to overload the proposal with that. If this is the only issue, it can be solved very easily.

the problem that it solves is many orders of magnitude less important than strong typing

This is a matter of opinion. I think that it’s just as important, but it should be many orders of magnitude easier to implement.

A "local" access modifier is not a breakthrough solution that will make it substantially easier to statically reason about programs to make them faster, provide refactoring tools, or help editing.

Not a breakthrough at all — it’s a basic feature that any language that supports OOP should have. But it does make it substantially easier to eliminate human error due to accidental misuse of APIs that are intended to be completely hidden and today cannot be.

It's a design tool intended for humans only, and it's extremely ambiguous with private.

It’s a tool for both humans and the compiler. Humans can clearly see the author’s intent, and the compiler can enforce it.

It’s not ambiguous at all: “private’ (really should be “file internal”) is to hide visibility in the same file. “local” is to hide it inside the class (or extension). The only ambiguous part is the naming. The original name (“private”) is unfortunate. I’d be happy to change it, but I am not sure if it’s possible at this point.

A new programmer makes a class and asks you if fields and methods should be private or local. What do you tell him?

local, of course. Only the public class API should be exposed to the outside world. “private” is a trade-off, similar to “friend” in C++. Unless that trade-off is necessary, there is no need to use “private” the way it is today (if we had “local”).

···

On Jan 25, 2016, at 3:26 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I don't understand your conception of encapsulation. The way you're putting it, because of Swift's access modifiers, encapsulation is relative to whether you have access to the original source or not. However, this is trivially true in any condition and whether Swift promoted a "private" or "local" access modifier would change nothing to it.

In my opinion, this solution will be confusing to a lot of people, and the problem that it solves is many orders of magnitude less important than strong typing. A "local" access modifier is not a breakthrough solution that will make it substantially easier to statically reason about programs to make them faster, provide refactoring tools, or help editing. It's a design tool intended for humans only, and it's extremely ambiguous with private.

A new programmer makes a class and asks you if fields and methods should be private or local. What do you tell him?

Félix

Le 25 janv. 2016 à 14:33:18, Ilya Belenkiy <ilya.belenkiy@gmail.com <mailto:ilya.belenkiy@gmail.com>> a écrit :

There would be no difference at all between local and private if you had one class per file.

AND if this rule was enforced by the compiler. This would also have to be one extension per file, even if it’s one line of code.

Since this rule is not enforced, at most, this is coding by convention. By the same reasoning, we could have just one type, object, and name every variable by including the type name we want it to be. No need for a strong type system. And anyone insisting that we need a type system would surely be wrong because there would be a very simple solution — just make the type name part of the variable name. And yet, Swift does have a strong type system. It should have strong access control for the very same reason: the compiler can enforce it and eliminate lots of human errors.

It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

And yet both statements are true: it is possible to break the class invariant right now without modifying the class source code, and “local” would solve that problem.

On Jan 25, 2016, at 1:43 PM, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

There would be no difference at all between local and private if you had one class per file. It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

Félix

Le 25 janv. 2016 à 13:16:45, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

A language does not need to have strict access controls in order to be considered OO.

This is a matter of terminology. It still doesn’t change the fact that data encapsulation is a fundamental feature of object oriented programming that is currently not supported.

You don’t even need “classes” to do OO either.

In this terminology C is also object oriented. You can have opaque pointers to structs with functions around them. Swift current support for data encapsulation is exactly like that. But people don’t do this kind of programming in C precisely because the compiler can provide a lot more help than this.

This really seems like an academic problem vs a pragmatic problem.

It’s very pragmatic. With properly marked access level and well designed interfaces, the class implementor may rely on the compiler to ensure that the class invariants / internal state will not become corrupt. Without it, the code is much more likely to break due to human error. It’s the same reasoning as with having ARC rather than doing manual retain / release and having destructors that are called automatically instead of calling cleanup code manually.

There’s also no concept of “friend” in Swift either

file based access level is a good solution for this. But it’s not a solution at all for real data encapsulation.

On Jan 25, 2016, at 12:09 PM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

On Jan 25, 2016, at 4:47 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data encapsulation is indeed one of the cornerstone of OO, but every design decision is a trade-off. Is Python not object-oriented because they lack a private keyword, and have the convention of marking internal items with a leading underscore?

Then Python has the same problem. A language that *supports* OOP should not leave such an important part of OOP to coding by convention.

I think this where you are being lead astray. A language does not need to have strict access controls in order to be considered OO. Languages like C#, Java, and to some extent, C++ tend to make people think this. You don’t even need “classes” to do OO either.

The best anyone can do is make the breaking of encapsulation an explicit choice. I’m intuiting that you think that writing code into the file where the class was defined is not explicit enough.

Right now, it’s impossible to make the distinction: is something truly private or can be used safely in the same file? The language has no way of expressing it. The class internal state is not encapsulated outside the bounds of the class.

This really seems like an academic problem vs a pragmatic problem. There’s also no concept of “friend” in Swift either, which is another construct that would have be invented to allow the “private” things to be used by others elsewhere.

-David

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

Why should the compiler enforce this? That’s my design decision.

It would enforce whatever design decision you make.

For the same reason the compiler does not enforce where I have to put „private“ (it can make suggestions like many IDEs do and offer fix-its, like „this method can be made private as it is not used outside the class“ or „this class can be put into its own file as its private methods are not used by other components in this file“.

But once you do put it, it enforces it, and that’s the whole point of having access control.

No, there is a clear difference: making the type name part of the variable name enforces no compiler checks whereas putting something into different files does.

Similarly, putting all of the source code in the same file is equivalent to no checks.

But you need to modify the file. With „local“ it is possible to break the class invariant without modifying the source code of a private method just by adding some public methods that call the private ones. Seems quite the same to me.

No because then you change the class definition itself.

I would wish for a better name, though…

Me too. I wish “private” was “file internal” and “local” could be “private”. But the right name is already taken.

···

On Jan 25, 2016, at 4:44 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 25.01.2016 um 20:33 schrieb Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

There would be no difference at all between local and private if you had one class per file.

AND if this rule was enforced by the compiler. This would also have to be one extension per file, even if it’s one line of code.

Why should the compiler enforce this? That’s my design decision.
For the same reason the compiler does not enforce where I have to put „private“ (it can make suggestions like many IDEs do and offer fix-its, like „this method can be made private as it is not used outside the class“ or „this class can be put into its own file as its private methods are not used by other components in this file“.

Since this rule is not enforced, at most, this is coding by convention. By the same reasoning, we could have just one type, object, and name every variable by including the type name we want it to be. No need for a strong type system. And anyone insisting that we need a type system would surely be wrong because there would be a very simple solution — just make the type name part of the variable name.

No, there is a clear difference: making the type name part of the variable name enforces no compiler checks whereas putting something into different files does.

And yet, Swift does have a strong type system. It should have strong access control for the very same reason: the compiler can enforce it and eliminate lots of human errors.

It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

And yet both statements are true: it is possible to break the class invariant right now without modifying the class source code, and “local” would solve that problem.

But you need to modify the file. With „local“ it is possible to break the class invariant without modifying the source code of a private method just by adding some public methods that call the private ones. Seems quite the same to me.

That being said I have nothing against a „local“ access modifier but I personally don’t see a real need for it. I would wish for a better name, though...

-Thorsten

On Jan 25, 2016, at 1:43 PM, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

There would be no difference at all between local and private if you had one class per file. It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

Félix

Le 25 janv. 2016 à 13:16:45, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

A language does not need to have strict access controls in order to be considered OO.

This is a matter of terminology. It still doesn’t change the fact that data encapsulation is a fundamental feature of object oriented programming that is currently not supported.

You don’t even need “classes” to do OO either.

In this terminology C is also object oriented. You can have opaque pointers to structs with functions around them. Swift current support for data encapsulation is exactly like that. But people don’t do this kind of programming in C precisely because the compiler can provide a lot more help than this.

This really seems like an academic problem vs a pragmatic problem.

It’s very pragmatic. With properly marked access level and well designed interfaces, the class implementor may rely on the compiler to ensure that the class invariants / internal state will not become corrupt. Without it, the code is much more likely to break due to human error. It’s the same reasoning as with having ARC rather than doing manual retain / release and having destructors that are called automatically instead of calling cleanup code manually.

There’s also no concept of “friend” in Swift either

file based access level is a good solution for this. But it’s not a solution at all for real data encapsulation.

On Jan 25, 2016, at 12:09 PM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

On Jan 25, 2016, at 4:47 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data encapsulation is indeed one of the cornerstone of OO, but every design decision is a trade-off. Is Python not object-oriented because they lack a private keyword, and have the convention of marking internal items with a leading underscore?

Then Python has the same problem. A language that *supports* OOP should not leave such an important part of OOP to coding by convention.

I think this where you are being lead astray. A language does not need to have strict access controls in order to be considered OO. Languages like C#, Java, and to some extent, C++ tend to make people think this. You don’t even need “classes” to do OO either.

The best anyone can do is make the breaking of encapsulation an explicit choice. I’m intuiting that you think that writing code into the file where the class was defined is not explicit enough.

Right now, it’s impossible to make the distinction: is something truly private or can be used safely in the same file? The language has no way of expressing it. The class internal state is not encapsulated outside the bounds of the class.

This really seems like an academic problem vs a pragmatic problem. There’s also no concept of “friend” in Swift either, which is another construct that would have be invented to allow the “private” things to be used by others elsewhere.

-David

_______________________________________________
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

Why should the compiler enforce this? That’s my design decision.

It would enforce whatever design decision you make.

For the same reason the compiler does not enforce where I have to
put „private“ (it can make suggestions like many IDEs do and offer
fix-its, like „this method can be made private as it is not used
outside the class“ or „this class can be put into its own file as
its private methods are not used by other components in this file“.

But once you do put it, it enforces it, and that’s the whole point of having access control.

No, there is a clear difference: making the type name part of the
variable name enforces no compiler checks whereas putting something
into different files does.

Similarly, putting all of the source code in the same file is
equivalent to no checks.

The place where I'm most concerned about this is in playgrounds. If
we're going to use them to teach programming, it should be possible to
demonstrate encapsulation there.

Using playgrounds for teaching is a great example of a use case for this. Thanks for mentioning it!

I also think the fact that “surrounding scope” is actually the most frequent use of `private` members (in code I have surveyed) indicates that it is a very reasonable feature request. Allowing us to declare the actual intent aids readability and clarity.

-Matthew

···

On Jan 25, 2016, at 5:47 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Mon Jan 25 2016, Ilya Belenkiy <swift-evolution@swift.org> wrote:

--
-Dave

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

Just to add my thoughts to this increasingly convoluted thread, but while I agree that the way that private works right now is fine for most purposes, I would also like to see a Java style protected option as well for many of the reasons mentioned, but most importantly that it allows me to define an abstract or sub-classable type in one file, and have it sub-classed elsewhere without having to expose internal, sub-class only, methods to everything else.

That said, in Swift the ability to put actual code in extensions largely eliminates the need for abstract classes, which cuts down on quite a lot of necessary sub-classing, at least in my experience. But still, private isn’t ideal for keep sub-class only methods hidden; keeping stuff like that hidden is nice purely from a clutter/auto-complete perspective, let alone the requirement it puts on teams to have a naming convention for sub-class oriented methods.

I feel the discussion is starting to get a bit circular :) At this point, think it is important to try to discover additional benefits of both solutions rather then reiterating the same arguments, so I think that Matthew is going the right direction by trying to bring practical aspects of the issue into the view. So far, the presented arguments were mostly ideological. As far as I understand it, Ilya’s point is based around a very rigorous notion of encapsulation (which I personally disagree with, but it doesn’t matter) and the necessity to enforce the design invariants. The definition scope access here aids as a safeguard that separates the public and the private interface. This is obviously an important feature and the reasoning is principally valid. On the other side, the opponents argue that such separation is barely useful on practice, because a single file in a well designed code is usually restricted to a few closely related declarations, so the chance to mix up the private and the public interface is actually pretty slim. And the private interface is invisible outside the file level, so the large scale aspect of this issue never becomes valid. There is undoubtedly some truth in this as well. Personally, I would be ok with either, but I am more tending towards the view that definition scope access is unnecessary. Let me present some arguments:

1. It only solves a small subset of a larger problem. If we really give were to stress the importance of enforced design invariants that much, then definition scope access is actually not enough. What we really need is a permission system, where we describe the exact usage of a member, e.g. this method can be only called from that one or this method can’t be called if the state is like this etc. In the end, unless we have built-in means to prove our code, invariants need to be tested with tests and assertions — and these should catch any misuse of private APIs.

2. The problem it solves is arguably barely worth mentioning. How often do you have to add principally new types to a file with other declarations? How often is it easy to confuse private and public interfaces? It is really such a common thing to accidentally misuse an API and do not notice it? Usually, I would not bring any substantial functionality into a source file written by others without first gaining basic understanding about the other contents of that file. And also, usually, if I am about to bring any substantial functionality into a source file written by others, I do it because I understand what is going on there and I just want to improve/enhance something. For instance (to bring some anecdotic evidence into play), I am mainly working with a language that lacks any access declarations whatsoever (R), and I never really had an issue with this. And I am often employing techniques which involve metaprogramming and on-the-fly replacement of definition scopes, so its fairly complex stuff. It is usually very clear which functionality is meant to be private and which is meant to be public, and to be honest, I quite frequently find myself accusing the private one for a number of reasons (usually efficiency and performance).

3. It assumes that the designer gets the design correct on the first try. How do you know whether you should declare a property local or private? Maybe you start as local (default) but at some point realise that it would be useful to open it up to other scopes for efficiency/other reasons? Especially in the initial design phase, there is a lot of moving around. Redeclaring invariants is not without effort, even though this is a very minor criticism point. Just wanted to mention it for the sake of completeness (of what came into my mind).

4. It hinders competent extenders. Imagine you understand the code really well. You want to add a new auxiliary public function, and it would be much more efficient if you accessed the private interface directly. However, the original designer did not anticipate your use case, so they declared that interface local. So you’d need to go and change the modifiers to private, which is kind of unnecessary effort.

To sum it up, I believe that restricting access like that gives you a sense of false security. It is not really likely to prevent bugs from happening, but it does limit the extendability of the code. The issues it aims to solved can be easily solved by minimal degree of coding discipline (such as: do not go changing around stuff in a file unless you understand what you are doing) and I doubt that experienced programmers are likely to encounter these issues very frequently (I know I never did, and I wouldn’t even call myself that experienced). Code testing should be performed by debug assertions and unit tests, which will easily detect any relevant case of API misuse. In the end, I believe that definition scope restricts mostly for ideological, but not practical reasons, given the coding style most appropriate with Swift.

Can we add a definition scope access to Swift? Sure, it won’t change much. Will we benefit from this change? I doubt so. The current system is good enough and its quite elegant in allowing one to implement tightly related functionality.

Finally some comments on Matthew’s post

In some cases, this is because there is a nested type involved and the `private` members are inside the nested type. They should not be visible outside the scope of the nested type.

But sometimes, if one wants to extend functionality or improve efficiency, and know what they are doing, having access to these private members could be beneficial. If they should not be visible outside of the scope in the first place, the person who implements the container type probably knows it and is unlikely to access them directly

One other case that didn’t appear in Alamofire, but I have seen elsewhere is a case where you conform several types to the same protocol (usually a simple protocol) in the same file. In this case there may be helper methods that support the protocol implementation but should not be visible to the other implementations of the protocol that are in the same file.

How likely is one to call one of those helper methods in actual code? I don’t see any potential for confusion at all. Unless you are working on a type that extents the type with the private method, but it doesn’t seem to be your example

It seems like “current scope” is probably the most frequent intent of `private`

That is undoubtedly true. However, the question should be put the other way: how frequently does the file scope obscure, obfuscate or otherwise denies this frequent use?

I suggest those who are pushing back on this look through some real-world code. How often do you actually need the file-level visibility of a `private` member? This is likely only needed in a significant minority of uses of `private`.

Personally, I use it quite often because of the way I like to design things as groups of tightly interdependent components (friends, if you want) who are aware of each other’s inner workings. I also want to have full access to the interface of any project I work on because I trust myself to make the judgement whether I am allowed to use a particular functionality or not. Definition scope restricts me without giving me any benefit I can immediately recognise.

Best,

Taras

···

On 25 Jan 2016, at 23:16, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

I want to try and offer a concrete example of the usefulness of this idea in real code. I had a look through the popular Alamofire library. Every use of `private` in that library could actually use `local` instead if it existed.

In some cases these would be equivalent because there is only one type / scope in the file anyway. However, in most cases they actually do communicate something different. There are a few ways this is possible:

In some cases, this is because there is a nested type involved and the `private` members are inside the nested type. They should not be visible outside the scope of the nested type.

In other cases, there are extensions of other types. These extensions add methods that are closely related to the primary type / extension involved in the file. The private members of the type

One other case that didn’t appear in Alamofire, but I have seen elsewhere is a case where you conform several types to the same protocol (usually a simple protocol) in the same file. In this case there may be helper methods that support the protocol implementation but should not be visible to the other implementations of the protocol that are in the same file.

It seems like “current scope” is probably the most frequent intent of `private`, while `file` is actually less commonly necessary, but is certainly the right thing in some cases (and is much better than `friend`).

I agree with Ilya that it would probably be better if `private` was actually scope-based. Rather than `internal` we could have `module` and `file` access modifiers to make it clear when there is broader visibility and make it clear exactly what that visibility is. This would be my preference and I think it would provide the most clarity.

On the other hand, changing the meaning of `private` is probably not going to happen at this point (or would at least likely receive even more pushback than `local`), thus the proposal to add a new modifier and not change the meaning of existing modifiers.

I suggest those who are pushing back on this look through some real-world code. How often do you actually need the file-level visibility of a `private` member? This is likely only needed in a significant minority of uses of `private`.

Saying what you mean and meaning what you say adds clarity to the code. It helps readers and future maintainers of the code understand the thinking of the author. Right now, we do not have the ability to say what we actually mean with regards to access control in a significant number of cases. It is the inability to express the most frequent intent of `private` that Ilya’s proposal is attempting to address (while not taking away the necessary ability to share visibility within a file in some cases).

-Matthew

On Jan 25, 2016, at 3:44 PM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 25.01.2016 um 20:33 schrieb Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

There would be no difference at all between local and private if you had one class per file.

AND if this rule was enforced by the compiler. This would also have to be one extension per file, even if it’s one line of code.

Why should the compiler enforce this? That’s my design decision.
For the same reason the compiler does not enforce where I have to put „private“ (it can make suggestions like many IDEs do and offer fix-its, like „this method can be made private as it is not used outside the class“ or „this class can be put into its own file as its private methods are not used by other components in this file“.

Since this rule is not enforced, at most, this is coding by convention. By the same reasoning, we could have just one type, object, and name every variable by including the type name we want it to be. No need for a strong type system. And anyone insisting that we need a type system would surely be wrong because there would be a very simple solution — just make the type name part of the variable name.

No, there is a clear difference: making the type name part of the variable name enforces no compiler checks whereas putting something into different files does.

And yet, Swift does have a strong type system. It should have strong access control for the very same reason: the compiler can enforce it and eliminate lots of human errors.

It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

And yet both statements are true: it is possible to break the class invariant right now without modifying the class source code, and “local” would solve that problem.

But you need to modify the file. With „local“ it is possible to break the class invariant without modifying the source code of a private method just by adding some public methods that call the private ones. Seems quite the same to me.

That being said I have nothing against a „local“ access modifier but I personally don’t see a real need for it. I would wish for a better name, though...

-Thorsten

On Jan 25, 2016, at 1:43 PM, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

There would be no difference at all between local and private if you had one class per file. It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

Félix

Le 25 janv. 2016 à 13:16:45, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

A language does not need to have strict access controls in order to be considered OO.

This is a matter of terminology. It still doesn’t change the fact that data encapsulation is a fundamental feature of object oriented programming that is currently not supported.

You don’t even need “classes” to do OO either.

In this terminology C is also object oriented. You can have opaque pointers to structs with functions around them. Swift current support for data encapsulation is exactly like that. But people don’t do this kind of programming in C precisely because the compiler can provide a lot more help than this.

This really seems like an academic problem vs a pragmatic problem.

It’s very pragmatic. With properly marked access level and well designed interfaces, the class implementor may rely on the compiler to ensure that the class invariants / internal state will not become corrupt. Without it, the code is much more likely to break due to human error. It’s the same reasoning as with having ARC rather than doing manual retain / release and having destructors that are called automatically instead of calling cleanup code manually.

There’s also no concept of “friend” in Swift either

file based access level is a good solution for this. But it’s not a solution at all for real data encapsulation.

On Jan 25, 2016, at 12:09 PM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

On Jan 25, 2016, at 4:47 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data encapsulation is indeed one of the cornerstone of OO, but every design decision is a trade-off. Is Python not object-oriented because they lack a private keyword, and have the convention of marking internal items with a leading underscore?

Then Python has the same problem. A language that *supports* OOP should not leave such an important part of OOP to coding by convention.

I think this where you are being lead astray. A language does not need to have strict access controls in order to be considered OO. Languages like C#, Java, and to some extent, C++ tend to make people think this. You don’t even need “classes” to do OO either.

The best anyone can do is make the breaking of encapsulation an explicit choice. I’m intuiting that you think that writing code into the file where the class was defined is not explicit enough.

Right now, it’s impossible to make the distinction: is something truly private or can be used safely in the same file? The language has no way of expressing it. The class internal state is not encapsulated outside the bounds of the class.

This really seems like an academic problem vs a pragmatic problem. There’s also no concept of “friend” in Swift either, which is another construct that would have be invented to allow the “private” things to be used by others elsewhere.

-David

_______________________________________________
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

  If we're going to use them to teach programming, it should be possible to
demonstrate encapsulation there.

A very important use case. In addition, it would be especially sad if there was a workaround for this particular case, and students learned the concept but could not apply it in real Swift code.

···

On Jan 25, 2016, at 8:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 25, 2016, at 5:47 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Mon Jan 25 2016, Ilya Belenkiy <swift-evolution@swift.org> wrote:

Why should the compiler enforce this? That’s my design decision.

It would enforce whatever design decision you make.

For the same reason the compiler does not enforce where I have to
put „private“ (it can make suggestions like many IDEs do and offer
fix-its, like „this method can be made private as it is not used
outside the class“ or „this class can be put into its own file as
its private methods are not used by other components in this file“.

But once you do put it, it enforces it, and that’s the whole point of having access control.

No, there is a clear difference: making the type name part of the
variable name enforces no compiler checks whereas putting something
into different files does.

Similarly, putting all of the source code in the same file is
equivalent to no checks.

The place where I'm most concerned about this is in playgrounds. If
we're going to use them to teach programming, it should be possible to
demonstrate encapsulation there.

Using playgrounds for teaching is a great example of a use case for this. Thanks for mentioning it!

I also think the fact that “surrounding scope” is actually the most frequent use of `private` members (in code I have surveyed) indicates that it is a very reasonable feature request. Allowing us to declare the actual intent aids readability and clarity.

-Matthew

--
-Dave

_______________________________________________
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

I like file scoped private, it's way better than C++'s `friend`. I also
often feel that it's unsafe when I've mentally scoped implementation
details to a class or extension, but the implementations are in the same
file.

I would support something like this:
    * `private(module)` alternatively `internal`, the default.
    * `private` alternatively `private(file)`
    * `private(class)`
    * `private(extension)`
    * `public`

Perhaps this could let us deprecate/remove the keyword `internal`, I'm not
sure of many circumstances when you'd actually need to write it.

I also think that `private(module)` is also more intuitively understood
than `internal`.

*My reasoning:*

This seems to come down to:

   - It lowers the cognitive load if you can put related concepts in the
   same file.
   - It lowers the cognitive load if you can reduce the number of things a
   class needs to understand.
   - People like the current system, its simple and it works for them.

"Everyone knows that debugging is twice as hard as writing a program in the
first place. So if you're as clever as you can be when you write it, how
will you ever debug it?" - The Elements of Programming Style

···

On Tue, Jan 26, 2016 at 12:46 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

> On Jan 25, 2016, at 5:47 PM, Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
> on Mon Jan 25 2016, Ilya Belenkiy <swift-evolution@swift.org> wrote:
>
>>> Why should the compiler enforce this? That’s my design decision.
>>
>> It would enforce whatever design decision you make.
>>
>>> For the same reason the compiler does not enforce where I have to
>>> put „private“ (it can make suggestions like many IDEs do and offer
>>> fix-its, like „this method can be made private as it is not used
>>> outside the class“ or „this class can be put into its own file as
>>> its private methods are not used by other components in this file“.
>>
>> But once you do put it, it enforces it, and that’s the whole point of
having access control.
>>
>>> No, there is a clear difference: making the type name part of the
>>> variable name enforces no compiler checks whereas putting something
>>> into different files does.
>>
>> Similarly, putting all of the source code in the same file is
>> equivalent to no checks.
>
> The place where I'm most concerned about this is in playgrounds. If
> we're going to use them to teach programming, it should be possible to
> demonstrate encapsulation there.
>

Using playgrounds for teaching is a great example of a use case for this.
Thanks for mentioning it!

I also think the fact that “surrounding scope” is actually the most
frequent use of `private` members (in code I have surveyed) indicates that
it is a very reasonable feature request. Allowing us to declare the actual
intent aids readability and clarity.

-Matthew

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

Sorry if I've missed it, but I didn't see these comments addressed in a way that I thought was sufficient.

The place where I'm most concerned about this is in playgrounds. If
we're going to use them to teach programming, it should be possible to
demonstrate encapsulation there.

Playgrounds support multiple files. Doesn't this alleviate this problem? Of course you can't model Swift's model in a single-file, but that's by-design.

Aside from that, as has been noted several times, the most common need is “current scope only”. It would be nice if that could actually be expressed in the language. There are often valid reasons to organize code such that more than one scope exists in the same file without a desire to share implementation details between the scopes. Right now there is a tension between code layout and the visibility semantics we actually desire and intend.

I disagree. You can pattern your code so that this appears to be the "most common need", but you can also pattern identical functioning code so that this feature doesn't even work.

For instance, I know in my code, this really isn't the "most common need". In fact, in nearly all of my code, local would be completely useless because I put the majority of my APIs in extensions. I like to model the data on the type definition and the APIs in extensions.

This proposal would make using extensions as a means of grouping functionality impossible:

struct Foo {
    local count: Int = 0
}

extension Foo {
    func hidden() { count += 1 } // error: count is not visible
}

So now we have to arbitrarily make `count` private, move `hidden()` into the `Foo` definition, or make `local` a whole lot more complicated.

If you design and write your code like you do in other languages, then ok, I can see a margin of usefulness from `local`.

-David

···

On Jan 25, 2016, at 3:47 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
On Jan 27, 2016, at 7:44 AM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

Why should the compiler enforce this? That’s my design decision.

It would enforce whatever design decision you make.

It does enforce my design decision. If I decide to put several things into the same file this is a design decision stating that I want them being able to access their private members and other code outside of this file to not being able to do that. This is enforced.
Conversely if I don't want shared access, I put them into different files. Both design decisions are supported by the compiler.

For the same reason the compiler does not enforce where I have to put „private“ (it can make suggestions like many IDEs do and offer fix-its, like „this method can be made private as it is not used outside the class“ or „this class can be put into its own file as its private methods are not used by other components in this file“.

But once you do put it, it enforces it, and that’s the whole point of having access control.

Exactly and the compiler does support and enforce my decisions.

No, there is a clear difference: making the type name part of the variable name enforces no compiler checks whereas putting something into different files does.

Similarly, putting all of the source code in the same file is equivalent to no checks.

No, that's the equivalent to not putting type information in the variable name.
In you naming example there is no difference, as nothing is enforced.
With putting things in different files the compiler enforces that private access is not possible. Just like I intended. If I put them into the same file I'm stating that private access is allowed, so there is nothing to enforce.

But you need to modify the file. With „local“ it is possible to break the class invariant without modifying the source code of a private method just by adding some public methods that call the private ones. Seems quite the same to me.

No because then you change the class definition itself.

You are changing code within the boundary of your (intended) access control. No difference there.

-Thorsten

···

Am 25.01.2016 um 23:03 schrieb Ilya Belenkiy <ilya.belenkiy@gmail.com>:

I would wish for a better name, though…

Me too. I wish “private” was “file internal” and “local” could be “private”. But the right name is already taken.

On Jan 25, 2016, at 4:44 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 25.01.2016 um 20:33 schrieb Ilya Belenkiy via swift-evolution <swift-evolution@swift.org>:

There would be no difference at all between local and private if you had one class per file.

AND if this rule was enforced by the compiler. This would also have to be one extension per file, even if it’s one line of code.

Why should the compiler enforce this? That’s my design decision.
For the same reason the compiler does not enforce where I have to put „private“ (it can make suggestions like many IDEs do and offer fix-its, like „this method can be made private as it is not used outside the class“ or „this class can be put into its own file as its private methods are not used by other components in this file“.

Since this rule is not enforced, at most, this is coding by convention. By the same reasoning, we could have just one type, object, and name every variable by including the type name we want it to be. No need for a strong type system. And anyone insisting that we need a type system would surely be wrong because there would be a very simple solution — just make the type name part of the variable name.

No, there is a clear difference: making the type name part of the variable name enforces no compiler checks whereas putting something into different files does.

And yet, Swift does have a strong type system. It should have strong access control for the very same reason: the compiler can enforce it and eliminate lots of human errors.

It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

And yet both statements are true: it is possible to break the class invariant right now without modifying the class source code, and “local” would solve that problem.

But you need to modify the file. With „local“ it is possible to break the class invariant without modifying the source code of a private method just by adding some public methods that call the private ones. Seems quite the same to me.

That being said I have nothing against a „local“ access modifier but I personally don’t see a real need for it. I would wish for a better name, though...

-Thorsten

On Jan 25, 2016, at 1:43 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

There would be no difference at all between local and private if you had one class per file. It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

Félix

Le 25 janv. 2016 à 13:16:45, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> a écrit :

A language does not need to have strict access controls in order to be considered OO.

This is a matter of terminology. It still doesn’t change the fact that data encapsulation is a fundamental feature of object oriented programming that is currently not supported.

You don’t even need “classes” to do OO either.

In this terminology C is also object oriented. You can have opaque pointers to structs with functions around them. Swift current support for data encapsulation is exactly like that. But people don’t do this kind of programming in C precisely because the compiler can provide a lot more help than this.

This really seems like an academic problem vs a pragmatic problem.

It’s very pragmatic. With properly marked access level and well designed interfaces, the class implementor may rely on the compiler to ensure that the class invariants / internal state will not become corrupt. Without it, the code is much more likely to break due to human error. It’s the same reasoning as with having ARC rather than doing manual retain / release and having destructors that are called automatically instead of calling cleanup code manually.

There’s also no concept of “friend” in Swift either

file based access level is a good solution for this. But it’s not a solution at all for real data encapsulation.

On Jan 25, 2016, at 12:09 PM, David Owens II <david@owensd.io> wrote:

On Jan 25, 2016, at 4:47 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

Data encapsulation is indeed one of the cornerstone of OO, but every design decision is a trade-off. Is Python not object-oriented because they lack a private keyword, and have the convention of marking internal items with a leading underscore?

Then Python has the same problem. A language that *supports* OOP should not leave such an important part of OOP to coding by convention.

I think this where you are being lead astray. A language does not need to have strict access controls in order to be considered OO. Languages like C#, Java, and to some extent, C++ tend to make people think this. You don’t even need “classes” to do OO either.

The best anyone can do is make the breaking of encapsulation an explicit choice. I’m intuiting that you think that writing code into the file where the class was defined is not explicit enough.

Right now, it’s impossible to make the distinction: is something truly private or can be used safely in the same file? The language has no way of expressing it. The class internal state is not encapsulated outside the bounds of the class.

This really seems like an academic problem vs a pragmatic problem. There’s also no concept of “friend” in Swift either, which is another construct that would have be invented to allow the “private” things to be used by others elsewhere.

-David

_______________________________________________
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

I feel the discussion is starting to get a bit circular :) At this point, think it is important to try to discover additional benefits of both solutions rather then reiterating the same arguments, so I think that Matthew is going the right direction by trying to bring practical aspects of the issue into the view. So far, the presented arguments were mostly ideological. As far as I understand it, Ilya’s point is based around a very rigorous notion of encapsulation (which I personally disagree with, but it doesn’t matter) and the necessity to enforce the design invariants. The definition scope access here aids as a safeguard that separates the public and the private interface. This is obviously an important feature and the reasoning is principally valid. On the other side, the opponents argue that such separation is barely useful on practice, because a single file in a well designed code is usually restricted to a few closely related declarations, so the chance to mix up the private and the public interface is actually pretty slim. And the private interface is invisible outside the file level, so the large scale aspect of this issue never becomes valid. There is undoubtedly some truth in this as well. Personally, I would be ok with either, but I am more tending towards the view that definition scope access is unnecessary. Let me present some arguments:

1. It only solves a small subset of a larger problem. If we really give were to stress the importance of enforced design invariants that much, then definition scope access is actually not enough. What we really need is a permission system, where we describe the exact usage of a member, e.g. this method can be only called from that one or this method can’t be called if the state is like this etc. In the end, unless we have built-in means to prove our code, invariants need to be tested with tests and assertions — and these should catch any misuse of private APIs.

Something like this is overkill. It gets really complex really fast to cover a minority of situations. What Ilya is proposing is simple and covers the majority of cases.

2. The problem it solves is arguably barely worth mentioning. How often do you have to add principally new types to a file with other declarations?

It is actually going to be pretty common in Swift to have members that should not reasonably accessed outside of their defining scope, while other scopes do exist in the same file. This is what I found in Alamofire. I chose that as an example of a popular and respected Swift code base that we all have access to. The pattern I found there holds in other code as well.

How often is it easy to confuse private and public interfaces? It is really such a common thing to accidentally misuse an API and do not notice it?

More important than preventing misuse is making intent and use clear. When I was looking through the Alamofire code I could “guess” that the `private` members were only accessed in the defining scope, but couldn’t know for sure until I searched their names throughout the file. It is helpful to know immediately the scope of possible use when reading code as it simplifies your mental model of the code.

Usually, I would not bring any substantial functionality into a source file written by others without first gaining basic understanding about the other contents of that file. And also, usually, if I am about to bring any substantial functionality into a source file written by others, I do it because I understand what is going on there and I just want to improve/enhance something. For instance (to bring some anecdotic evidence into play), I am mainly working with a language that lacks any access declarations whatsoever (R), and I never really had an issue with this. And I am often employing techniques which involve metaprogramming and on-the-fly replacement of definition scopes, so its fairly complex stuff. It is usually very clear which functionality is meant to be private and which is meant to be public, and to be honest, I quite frequently find myself accusing the private one for a number of reasons (usually efficiency and performance).

3. It assumes that the designer gets the design correct on the first try. How do you know whether you should declare a property local or private? Maybe you start as local (default) but at some point realise that it would be useful to open it up to other scopes for efficiency/other reasons?

How do you know `private` is right and not `internal`? The same concern potentially applies. In most cases you will have a reasonable idea of what your intent is. Of course any aspect of your code might change over time and this no exception.

Especially in the initial design phase, there is a lot of moving around. Redeclaring invariants is not without effort, even though this is a very minor criticism point. Just wanted to mention it for the sake of completeness (of what came into my mind).

4. It hinders competent extenders. Imagine you understand the code really well. You want to add a new auxiliary public function, and it would be much more efficient if you accessed the private interface directly. However, the original designer did not anticipate your use case, so they declared that interface local. So you’d need to go and change the modifiers to private, which is kind of unnecessary effort.

I don’t agree that it is unnecessary effort. First, if you add the `public` method in the same scope you don’t need to do anything. Second, if you add the `public` method anywhere other than the current file you already need to change to `internal` so there is no difference in effort. Only when you add a `public` member somewhere outside the same scope but inside the same file will any “additional” effort be necessary.

IMO it is a good thing that you need to consider what you are doing in this case. In many cases it will be perfectly fine and you will just change the access control. But in other cases, maybe there is more happening than you expected and you must take care in how you access the private member. In other cases, maybe you should add the `public` member inside the same scope rather than elsewhere in the same file, leaving access control intact. Stopping to consider these cases is not a bad thing.

To sum it up, I believe that restricting access like that gives you a sense of false security.
It is not really likely to prevent bugs from happening, but it does limit the extendability of the code.

It doesn’t limit extendability at all. As you noted, it is simple to increase visibility if you already have access to the file, allowing you to extend the code as you wish.

The issues it aims to solved can be easily solved by minimal degree of coding discipline (such as: do not go changing around stuff in a file unless you understand what you are doing) and I doubt that experienced programmers are likely to encounter these issues very frequently (I know I never did, and I wouldn’t even call myself that experienced). Code testing should be performed by debug assertions and unit tests, which will easily detect any relevant case of API misuse. In the end, I believe that definition scope restricts mostly for ideological, but not practical reasons, given the coding style most appropriate with Swift.

I know Ilya has been emphasizing the argument around protecting invariants. IMO the stronger argument is that the distinction between scope visibility and file visibility aids understanding of the intent and current usage of a member. Those who take advantage of the narrower, scope-based access modifier will find it is more common than file based visibility. They will be able to make more assumptions with certainty when reading code in their projects.

I agree that this is not a game-changer, but the benefit is also not trivial at all. It is easily significant enough to warrant a relatively simple feature addition IMO.

Can we add a definition scope access to Swift? Sure, it won’t change much. Will we benefit from this change? I doubt so. The current system is good enough and its quite elegant in allowing one to implement tightly related functionality.

Finally some comments on Matthew’s post

In some cases, this is because there is a nested type involved and the `private` members are inside the nested type. They should not be visible outside the scope of the nested type.

But sometimes, if one wants to extend functionality or improve efficiency, and know what they are doing, having access to these private members could be beneficial. If they should not be visible outside of the scope in the first place, the person who implements the container type probably knows it and is unlikely to access them directly

I don’t disagree. But this doesn’t allow the implementer to communicate their intent to readers of the code (unless they use comments).

One other case that didn’t appear in Alamofire, but I have seen elsewhere is a case where you conform several types to the same protocol (usually a simple protocol) in the same file. In this case there may be helper methods that support the protocol implementation but should not be visible to the other implementations of the protocol that are in the same file.

How likely is one to call one of those helper methods in actual code? I don’t see any potential for confusion at all. Unless you are working on a type that extents the type with the private method, but it doesn’t seem to be your example

It isn’t likely, but the point is that a scope-based access modifier would make the intent 100% clear, without question. There is no reason we should accept any doubt about intent when making the intent clear is a simple language enhancement that is actually the right thing in most cases (scope level visibility rather than file level visibility).

It seems like “current scope” is probably the most frequent intent of `private`

That is undoubtedly true. However, the question should be put the other way: how frequently does the file scope obscure, obfuscate or otherwise denies this frequent use?

Any time there is more than one scope there is at least some potential for this. As mentioned, I could not be sure in several cases when reading Alamofire without searching the file. I think the language should make it possible to specify intent clearly in the most common use case. It simply does not do that today.

I suggest those who are pushing back on this look through some real-world code. How often do you actually need the file-level visibility of a `private` member? This is likely only needed in a significant minority of uses of `private`.

Personally, I use it quite often because of the way I like to design things as groups of tightly interdependent components (friends, if you want) who are aware of each other’s inner workings.
I also want to have full access to the interface of any project I work on because I trust myself to make the judgement whether I am allowed to use a particular functionality or not. Definition scope restricts me without giving me any benefit I can immediately recognize.

Nobody is arguing that this should be the default or that you should be required to use it. If you don’t see the benefit you would not need to use it.

-Matthew

···

On Jan 25, 2016, at 5:40 PM, Taras Zakharko <taras.zakharko@uzh.ch> wrote:

Best,

Taras

On 25 Jan 2016, at 23:16, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I want to try and offer a concrete example of the usefulness of this idea in real code. I had a look through the popular Alamofire library. Every use of `private` in that library could actually use `local` instead if it existed.

In some cases these would be equivalent because there is only one type / scope in the file anyway. However, in most cases they actually do communicate something different. There are a few ways this is possible:

In some cases, this is because there is a nested type involved and the `private` members are inside the nested type. They should not be visible outside the scope of the nested type.

In other cases, there are extensions of other types. These extensions add methods that are closely related to the primary type / extension involved in the file. The private members of the type

One other case that didn’t appear in Alamofire, but I have seen elsewhere is a case where you conform several types to the same protocol (usually a simple protocol) in the same file. In this case there may be helper methods that support the protocol implementation but should not be visible to the other implementations of the protocol that are in the same file.

It seems like “current scope” is probably the most frequent intent of `private`, while `file` is actually less commonly necessary, but is certainly the right thing in some cases (and is much better than `friend`).

I agree with Ilya that it would probably be better if `private` was actually scope-based. Rather than `internal` we could have `module` and `file` access modifiers to make it clear when there is broader visibility and make it clear exactly what that visibility is. This would be my preference and I think it would provide the most clarity.

On the other hand, changing the meaning of `private` is probably not going to happen at this point (or would at least likely receive even more pushback than `local`), thus the proposal to add a new modifier and not change the meaning of existing modifiers.

I suggest those who are pushing back on this look through some real-world code. How often do you actually need the file-level visibility of a `private` member? This is likely only needed in a significant minority of uses of `private`.

Saying what you mean and meaning what you say adds clarity to the code. It helps readers and future maintainers of the code understand the thinking of the author. Right now, we do not have the ability to say what we actually mean with regards to access control in a significant number of cases. It is the inability to express the most frequent intent of `private` that Ilya’s proposal is attempting to address (while not taking away the necessary ability to share visibility within a file in some cases).

-Matthew

On Jan 25, 2016, at 3:44 PM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 25.01.2016 um 20:33 schrieb Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

There would be no difference at all between local and private if you had one class per file.

AND if this rule was enforced by the compiler. This would also have to be one extension per file, even if it’s one line of code.

Why should the compiler enforce this? That’s my design decision.
For the same reason the compiler does not enforce where I have to put „private“ (it can make suggestions like many IDEs do and offer fix-its, like „this method can be made private as it is not used outside the class“ or „this class can be put into its own file as its private methods are not used by other components in this file“.

Since this rule is not enforced, at most, this is coding by convention. By the same reasoning, we could have just one type, object, and name every variable by including the type name we want it to be. No need for a strong type system. And anyone insisting that we need a type system would surely be wrong because there would be a very simple solution — just make the type name part of the variable name.

No, there is a clear difference: making the type name part of the variable name enforces no compiler checks whereas putting something into different files does.

And yet, Swift does have a strong type system. It should have strong access control for the very same reason: the compiler can enforce it and eliminate lots of human errors.

It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

And yet both statements are true: it is possible to break the class invariant right now without modifying the class source code, and “local” would solve that problem.

But you need to modify the file. With „local“ it is possible to break the class invariant without modifying the source code of a private method just by adding some public methods that call the private ones. Seems quite the same to me.

That being said I have nothing against a „local“ access modifier but I personally don’t see a real need for it. I would wish for a better name, though...

-Thorsten

On Jan 25, 2016, at 1:43 PM, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

There would be no difference at all between local and private if you had one class per file. It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

Félix

Le 25 janv. 2016 à 13:16:45, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

A language does not need to have strict access controls in order to be considered OO.

This is a matter of terminology. It still doesn’t change the fact that data encapsulation is a fundamental feature of object oriented programming that is currently not supported.

You don’t even need “classes” to do OO either.

In this terminology C is also object oriented. You can have opaque pointers to structs with functions around them. Swift current support for data encapsulation is exactly like that. But people don’t do this kind of programming in C precisely because the compiler can provide a lot more help than this.

This really seems like an academic problem vs a pragmatic problem.

It’s very pragmatic. With properly marked access level and well designed interfaces, the class implementor may rely on the compiler to ensure that the class invariants / internal state will not become corrupt. Without it, the code is much more likely to break due to human error. It’s the same reasoning as with having ARC rather than doing manual retain / release and having destructors that are called automatically instead of calling cleanup code manually.

There’s also no concept of “friend” in Swift either

file based access level is a good solution for this. But it’s not a solution at all for real data encapsulation.

On Jan 25, 2016, at 12:09 PM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

On Jan 25, 2016, at 4:47 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data encapsulation is indeed one of the cornerstone of OO, but every design decision is a trade-off. Is Python not object-oriented because they lack a private keyword, and have the convention of marking internal items with a leading underscore?

Then Python has the same problem. A language that *supports* OOP should not leave such an important part of OOP to coding by convention.

I think this where you are being lead astray. A language does not need to have strict access controls in order to be considered OO. Languages like C#, Java, and to some extent, C++ tend to make people think this. You don’t even need “classes” to do OO either.

The best anyone can do is make the breaking of encapsulation an explicit choice. I’m intuiting that you think that writing code into the file where the class was defined is not explicit enough.

Right now, it’s impossible to make the distinction: is something truly private or can be used safely in the same file? The language has no way of expressing it. The class internal state is not encapsulated outside the bounds of the class.

This really seems like an academic problem vs a pragmatic problem. There’s also no concept of “friend” in Swift either, which is another construct that would have be invented to allow the “private” things to be used by others elsewhere.

-David

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

Phone doesn't like replying to the list, sorry.

···

Sent from my iPhone, please excuse brevity and errors

On Jan 25, 2016, at 8:32 PM, Nate Birkholz <nbirkholz@gmail.com> wrote:

Sent from my iPhone, please excuse brevity and errors

On Jan 25, 2016, at 8:22 PM, Rob Mayoff via swift-evolution <swift-evolution@swift.org> wrote:

Note that moving a private class to its own file to make its privates more private does not work. Now I have to make the formerly-private class an internal class, so I'm not sending the first message anymore.

Why do you have to make it internal then? I'm confused.

I like file scoped private, it's way better than C++'s `friend`. I also often feel that it's unsafe when I've mentally scoped implementation details to a class or extension, but the implementations are in the same file.

I would support something like this:
    * `private(module)` alternatively `internal`, the default.
    * `private` alternatively `private(file)`
    * `private(class)`
    * `private(extension)`
    * `public`

I like the basic breakdown of functionality here, but why overload private with so many variations? This is more verbose than necessary. I think we can get away with being more clear and concise (access modifiers are decl modifiers, not keywords so they don’t steal identifiers, IIUC).

Why not this:

    * `public`
    * `module`, the default (currently `internal`).
    * `file` (currently `private`)
    * `private` (no current equivalent: containing scope whether class, struct, enum, extension, etc)

···

On Jan 25, 2016, at 8:37 PM, Andrew Bennett <cacoyi@gmail.com> wrote:

Perhaps this could let us deprecate/remove the keyword `internal`, I'm not sure of many circumstances when you'd actually need to write it.

I also think that `private(module)` is also more intuitively understood than `internal`.

My reasoning:

This seems to come down to:
It lowers the cognitive load if you can put related concepts in the same file.
It lowers the cognitive load if you can reduce the number of things a class needs to understand.
People like the current system, its simple and it works for them.
"Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?" - The Elements of Programming Style

On Tue, Jan 26, 2016 at 12:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

> On Jan 25, 2016, at 5:47 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>
> on Mon Jan 25 2016, Ilya Belenkiy <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>>> Why should the compiler enforce this? That’s my design decision.
>>
>> It would enforce whatever design decision you make.
>>
>>> For the same reason the compiler does not enforce where I have to
>>> put „private“ (it can make suggestions like many IDEs do and offer
>>> fix-its, like „this method can be made private as it is not used
>>> outside the class“ or „this class can be put into its own file as
>>> its private methods are not used by other components in this file“.
>>
>> But once you do put it, it enforces it, and that’s the whole point of having access control.
>>
>>> No, there is a clear difference: making the type name part of the
>>> variable name enforces no compiler checks whereas putting something
>>> into different files does.
>>
>> Similarly, putting all of the source code in the same file is
>> equivalent to no checks.
>
> The place where I'm most concerned about this is in playgrounds. If
> we're going to use them to teach programming, it should be possible to
> demonstrate encapsulation there.
>

Using playgrounds for teaching is a great example of a use case for this. Thanks for mentioning it!

I also think the fact that “surrounding scope” is actually the most frequent use of `private` members (in code I have surveyed) indicates that it is a very reasonable feature request. Allowing us to declare the actual intent aids readability and clarity.

-Matthew

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

I agree with everything Matthew Johnson said in his response. In addition:

Personally, I use it quite often because of the way I like to design
things as groups of tightly interdependent components (friends, if you
want) who are aware of each other’s inner workings. I also want to have
full access to the interface of any project I work on because I trust
myself to make the judgement whether I am allowed to use a particular
functionality or not.

By this logic, you don't want or need private (Swift's private-to-file)
either. You just want/need internal and public, because you trust your
judgement and you want access to everything in the project.

I trust my judgement, but I don't trust my memory. In six months, I won't
remember every detail of the code I wrote today. Private-to-file is a
message from past-me to future-me: "Dear future-Rob, you don't need to
worry about looking for any use of this element outside this file, but if
you want to make it visible to other files, you better study it to make
sure it's safe to expose. Warmest regards, past-Rob."

This is a useful message. It helps jog future-Rob's memory, it saves
future-Rob from bugs, and it lets past-Rob rest easy because the message is
guaranteed to be delivered, and is guaranteed to be correct. No comment or
policy or convention can make that guarantee.

I want the ability to send another useful message: "Dear future-Rob, you
don't need to worry about looking for any use of this element outside this
class, but if you want to make it visible to other classes, you better
study it to make sure it's safe to expose. Very truly yours, past-Rob."

Note that moving a private class to its own file to make its privates more
private does not work. Now I have to make the formerly-private class an
internal class, so I'm not sending the first message anymore.

I'm not arguing that Swift needs, say, Scala's level of detail in its
access modifiers, but I think an access modifier for private-to-class or
private-to-instance or private-to-scope would let past-Rob convey useful
information to future-Rob in a lot of places where currently the
information is less precise or entirely absent, and that this ability is
useful enough to justify the additional language complexity.

···

On Mon, Jan 25, 2016 at 5:40 PM, Taras Zakharko via swift-evolution < swift-evolution@swift.org> wrote:

Note that moving a private class to its own file to make its privates

more private does not work. Now I have to make the formerly-private class
an internal class, so I'm not sending the first message anymore.

Why do you have to make it internal then? I'm confused.

In Scheduler.swift, I have public (or internal) class Scheduler, and it
uses private class JobRecord, also in Scheduler.swift.

I want to make some of JobRecord's members private to JobRecord. Right now,
the only way to do that is to move JobRecord to a separate file, say
JobRecord.swift, so that its privates become "more private" (since class
JobRecord is the only thing in JobRecord.swift).

But in order for JobRecord to be visible to Scheduler, I now have to change
"private class JobRecord" to "internal class JobRecord". The
message-to-future-Rob that JobRecord is only intended for use by
Scheduler.swift is lost (or at any rate its accuracy is no longer enforced
by the compiler).

···

On Mon, Jan 25, 2016 at 10:37 PM, Nate Birkholz via swift-evolution < swift-evolution@swift.org> wrote:

This a great writeup on clarity of intent. I’d like to add that in principle, if clarity of intent was the only goal, it could be achieved by a universally agreed on convention, like putting _ in front of the method or property (or type) . We could put it in guidelines and rely on it in all Swift projects. The other part that it is enforced by the compiler is equally important. The reasoning is the same as having real types instead of conventions for naming objects:

Imagine that the Swift compiler did nothing for types — it was just a useful way to convey the coder’s intent. Maintaining the code in this context would become much more difficult:

1) the compiler would not help catch mistakes.
2) the tools would not provide contextual auto completions or useful type related information in general

I am sure that everyone would be less comfortable shipping a large codebase that didn’t go through all the type checks. Exactly the same reasoning applies to “local”. If it’s just a convention that is not enforced by the compiler, we lose a very useful way to verify code correctness. In addition to that, everything that is marked as “local” (or “_” in front of the name) now shows up in code completions and adds noise and temptation to cut corners (often this would be “faster” functions that already assume certain things about the state that may generally not be true). There are plenty of discussions about Cocoa private APIs on the web where the only thing that is stopping people is whether using them will pass the app store check (and if there is a secret back door still). That specific boundary is addressed with “internal”, but the same is true at the scale of a class.

···

On Jan 25, 2016, at 11:22 PM, Rob Mayoff via swift-evolution <swift-evolution@swift.org> wrote:

I agree with everything Matthew Johnson said in his response. In addition:

On Mon, Jan 25, 2016 at 5:40 PM, Taras Zakharko via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Personally, I use it quite often because of the way I like to design things as groups of tightly interdependent components (friends, if you want) who are aware of each other’s inner workings. I also want to have full access to the interface of any project I work on because I trust myself to make the judgement whether I am allowed to use a particular functionality or not.

By this logic, you don't want or need private (Swift's private-to-file) either. You just want/need internal and public, because you trust your judgement and you want access to everything in the project.

I trust my judgement, but I don't trust my memory. In six months, I won't remember every detail of the code I wrote today. Private-to-file is a message from past-me to future-me: "Dear future-Rob, you don't need to worry about looking for any use of this element outside this file, but if you want to make it visible to other files, you better study it to make sure it's safe to expose. Warmest regards, past-Rob."

This is a useful message. It helps jog future-Rob's memory, it saves future-Rob from bugs, and it lets past-Rob rest easy because the message is guaranteed to be delivered, and is guaranteed to be correct. No comment or policy or convention can make that guarantee.

I want the ability to send another useful message: "Dear future-Rob, you don't need to worry about looking for any use of this element outside this class, but if you want to make it visible to other classes, you better study it to make sure it's safe to expose. Very truly yours, past-Rob."

Note that moving a private class to its own file to make its privates more private does not work. Now I have to make the formerly-private class an internal class, so I'm not sending the first message anymore.

I'm not arguing that Swift needs, say, Scala's level of detail in its access modifiers, but I think an access modifier for private-to-class or private-to-instance or private-to-scope would let past-Rob convey useful information to future-Rob in a lot of places where currently the information is less precise or entirely absent, and that this ability is useful enough to justify the additional language complexity.

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

I agree with everything Matthew Johnson said in his response. In addition:

Personally, I use it quite often because of the way I like to design things as groups of tightly interdependent components (friends, if you want) who are aware of each other’s inner workings. I also want to have full access to the interface of any project I work on because I trust myself to make the judgement whether I am allowed to use a particular functionality or not.

By this logic, you don't want or need private (Swift's private-to-file) either. You just want/need internal and public, because you trust your judgement and you want access to everything in the project.

I trust my judgement, but I don't trust my memory. In six months, I won't remember every detail of the code I wrote today. Private-to-file is a message from past-me to future-me: "Dear future-Rob, you don't need to worry about looking for any use of this element outside this file, but if you want to make it visible to other files, you better study it to make sure it's safe to expose. Warmest regards, past-Rob."

This is a useful message. It helps jog future-Rob's memory, it saves future-Rob from bugs, and it lets past-Rob rest easy because the message is guaranteed to be delivered, and is guaranteed to be correct. No comment or policy or convention can make that guarantee.

+1

I want the ability to send another useful message: "Dear future-Rob, you don't need to worry about looking for any use of this element outside this class, but if you want to make it visible to other classes, you better study it to make sure it's safe to expose. Very truly yours, past-Rob.”

+1

Note that moving a private class to its own file to make its privates more private does not work. Now I have to make the formerly-private class an internal class, so I'm not sending the first message anymore.

I'm not arguing that Swift needs, say, Scala's level of detail in its access modifiers, but I think an access modifier for private-to-class or private-to-instance or private-to-scope would let past-Rob convey useful information to future-Rob in a lot of places where currently the information is less precise or entirely absent, and that this ability is useful enough to justify the additional language complexity.

Exactly. It is significant benefit, at least to some of us, with a relatively minor cost in incremental complexity.

···

On Jan 25, 2016, at 10:22 PM, Rob Mayoff via swift-evolution <swift-evolution@swift.org> wrote:
On Mon, Jan 25, 2016 at 5:40 PM, Taras Zakharko via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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

It seems to be the opposite, these example work in a playground:

let public: Int = 123

error: keyword 'public' cannot be used as an identifier

However:

struct Test {

    private(set) var set: Int

}

no errors

I think that `module` and `file` without further context may be confusing.
I also think that `class` that I had is probably confusing.

I don't see the additional verbosity as a problem, I think the more
frequently used ones are probably fine.

I'm happy for them all to be keywords, the original proposal had some good
suggestions there, I just think what I've suggested is a bit nicer.

I think that what I'm suggesting would increase safety and granularity,
with only one new case you didn't have, and it would actually reduce the
number of keywords.

···

On Tue, Jan 26, 2016 at 1:51 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Jan 25, 2016, at 8:37 PM, Andrew Bennett <cacoyi@gmail.com> wrote:

I like file scoped private, it's way better than C++'s `friend`. I also
often feel that it's unsafe when I've mentally scoped implementation
details to a class or extension, but the implementations are in the same
file.

I would support something like this:
    * `private(module)` alternatively `internal`, the default.
    * `private` alternatively `private(file)`
    * `private(class)`
    * `private(extension)`
    * `public`

I like the basic breakdown of functionality here, but why overload private
with so many variations? This is more verbose than necessary. I think we
can get away with being more clear and concise (access modifiers are decl
modifiers, not keywords so they don’t steal identifiers, IIUC).

Why not this:

    * `public`
    * `module`, the default (currently `internal`).
    * `file` (currently `private`)
    * `private` (no current equivalent: containing scope whether class,
struct, enum, extension, etc)

Perhaps this could let us deprecate/remove the keyword `internal`, I'm
not sure of many circumstances when you'd actually need to write it.

I also think that `private(module)` is also more intuitively understood
than `internal`.

*My reasoning:*

This seems to come down to:

   - It lowers the cognitive load if you can put related concepts in the
   same file.
   - It lowers the cognitive load if you can reduce the number of things
   a class needs to understand.
   - People like the current system, its simple and it works for them.

"Everyone knows that debugging is twice as hard as writing a program in
the first place. So if you're as clever as you can be when you write it,
how will you ever debug it?" - The Elements of Programming Style

On Tue, Jan 26, 2016 at 12:46 PM, Matthew Johnson via swift-evolution < > swift-evolution@swift.org> wrote:

> On Jan 25, 2016, at 5:47 PM, Dave Abrahams via swift-evolution < >> swift-evolution@swift.org> wrote:
>
>
> on Mon Jan 25 2016, Ilya Belenkiy <swift-evolution@swift.org> wrote:
>
>>> Why should the compiler enforce this? That’s my design decision.
>>
>> It would enforce whatever design decision you make.
>>
>>> For the same reason the compiler does not enforce where I have to
>>> put „private“ (it can make suggestions like many IDEs do and offer
>>> fix-its, like „this method can be made private as it is not used
>>> outside the class“ or „this class can be put into its own file as
>>> its private methods are not used by other components in this file“.
>>
>> But once you do put it, it enforces it, and that’s the whole point of
having access control.
>>
>>> No, there is a clear difference: making the type name part of the
>>> variable name enforces no compiler checks whereas putting something
>>> into different files does.
>>
>> Similarly, putting all of the source code in the same file is
>> equivalent to no checks.
>
> The place where I'm most concerned about this is in playgrounds. If
> we're going to use them to teach programming, it should be possible to
> demonstrate encapsulation there.
>

Using playgrounds for teaching is a great example of a use case for
this. Thanks for mentioning it!

I also think the fact that “surrounding scope” is actually the most
frequent use of `private` members (in code I have surveyed) indicates that
it is a very reasonable feature request. Allowing us to declare the actual
intent aids readability and clarity.

-Matthew

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

Why should the compiler enforce this? That’s my design decision.

It would enforce whatever design decision you make.

It does enforce my design decision. If I decide to put several things into the same file this is a design decision stating that I want them being able to access their private members and other code outside of this file to not being able to do that. This is enforced.
Conversely if I don't want shared access, I put them into different files. Both design decisions are supported by the compiler.

What if we want shared access for some members but not others? It is not possible to express this or have the compiler enforce it today.

Aside from that, as has been noted several times, the most common need is “current scope only”. It would be nice if that could actually be expressed in the language. There are often valid reasons to organize code such that more than one scope exists in the same file without a desire to share implementation details between the scopes. Right now there is a tension between code layout and the visibility semantics we actually desire and intend.

-Matthew

···

On Jan 27, 2016, at 9:36 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:
Am 25.01.2016 um 23:03 schrieb Ilya Belenkiy <ilya.belenkiy@gmail.com <mailto:ilya.belenkiy@gmail.com>>:

For the same reason the compiler does not enforce where I have to put „private“ (it can make suggestions like many IDEs do and offer fix-its, like „this method can be made private as it is not used outside the class“ or „this class can be put into its own file as its private methods are not used by other components in this file“.

But once you do put it, it enforces it, and that’s the whole point of having access control.

Exactly and the compiler does support and enforce my decisions.

No, there is a clear difference: making the type name part of the variable name enforces no compiler checks whereas putting something into different files does.

Similarly, putting all of the source code in the same file is equivalent to no checks.

No, that's the equivalent to not putting type information in the variable name.
In you naming example there is no difference, as nothing is enforced.
With putting things in different files the compiler enforces that private access is not possible. Just like I intended. If I put them into the same file I'm stating that private access is allowed, so there is nothing to enforce.

But you need to modify the file. With „local“ it is possible to break the class invariant without modifying the source code of a private method just by adding some public methods that call the private ones. Seems quite the same to me.

No because then you change the class definition itself.

You are changing code within the boundary of your (intended) access control. No difference there.

-Thorsten

I would wish for a better name, though…

Me too. I wish “private” was “file internal” and “local” could be “private”. But the right name is already taken.

On Jan 25, 2016, at 4:44 PM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Am 25.01.2016 um 20:33 schrieb Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

There would be no difference at all between local and private if you had one class per file.

AND if this rule was enforced by the compiler. This would also have to be one extension per file, even if it’s one line of code.

Why should the compiler enforce this? That’s my design decision.
For the same reason the compiler does not enforce where I have to put „private“ (it can make suggestions like many IDEs do and offer fix-its, like „this method can be made private as it is not used outside the class“ or „this class can be put into its own file as its private methods are not used by other components in this file“.

Since this rule is not enforced, at most, this is coding by convention. By the same reasoning, we could have just one type, object, and name every variable by including the type name we want it to be. No need for a strong type system. And anyone insisting that we need a type system would surely be wrong because there would be a very simple solution — just make the type name part of the variable name.

No, there is a clear difference: making the type name part of the variable name enforces no compiler checks whereas putting something into different files does.

And yet, Swift does have a strong type system. It should have strong access control for the very same reason: the compiler can enforce it and eliminate lots of human errors.

It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

And yet both statements are true: it is possible to break the class invariant right now without modifying the class source code, and “local” would solve that problem.

But you need to modify the file. With „local“ it is possible to break the class invariant without modifying the source code of a private method just by adding some public methods that call the private ones. Seems quite the same to me.

That being said I have nothing against a „local“ access modifier but I personally don’t see a real need for it. I would wish for a better name, though...

-Thorsten

On Jan 25, 2016, at 1:43 PM, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

There would be no difference at all between local and private if you had one class per file. It seems very very bold to me to say that Swift "doesn't support encapsulation" but that local would solve that problem.

Félix

Le 25 janv. 2016 à 13:16:45, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

A language does not need to have strict access controls in order to be considered OO.

This is a matter of terminology. It still doesn’t change the fact that data encapsulation is a fundamental feature of object oriented programming that is currently not supported.

You don’t even need “classes” to do OO either.

In this terminology C is also object oriented. You can have opaque pointers to structs with functions around them. Swift current support for data encapsulation is exactly like that. But people don’t do this kind of programming in C precisely because the compiler can provide a lot more help than this.

This really seems like an academic problem vs a pragmatic problem.

It’s very pragmatic. With properly marked access level and well designed interfaces, the class implementor may rely on the compiler to ensure that the class invariants / internal state will not become corrupt. Without it, the code is much more likely to break due to human error. It’s the same reasoning as with having ARC rather than doing manual retain / release and having destructors that are called automatically instead of calling cleanup code manually.

There’s also no concept of “friend” in Swift either

file based access level is a good solution for this. But it’s not a solution at all for real data encapsulation.

On Jan 25, 2016, at 12:09 PM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

On Jan 25, 2016, at 4:47 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Data encapsulation is indeed one of the cornerstone of OO, but every design decision is a trade-off. Is Python not object-oriented because they lack a private keyword, and have the convention of marking internal items with a leading underscore?

Then Python has the same problem. A language that *supports* OOP should not leave such an important part of OOP to coding by convention.

I think this where you are being lead astray. A language does not need to have strict access controls in order to be considered OO. Languages like C#, Java, and to some extent, C++ tend to make people think this. You don’t even need “classes” to do OO either.

The best anyone can do is make the breaking of encapsulation an explicit choice. I’m intuiting that you think that writing code into the file where the class was defined is not explicit enough.

Right now, it’s impossible to make the distinction: is something truly private or can be used safely in the same file? The language has no way of expressing it. The class internal state is not encapsulated outside the bounds of the class.

This really seems like an academic problem vs a pragmatic problem. There’s also no concept of “friend” in Swift either, which is another construct that would have be invented to allow the “private” things to be used by others elsewhere.

-David

_______________________________________________
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

Sorry if I've missed it, but I didn't see these comments addressed in a way that I thought was sufficient.

The place where I'm most concerned about this is in playgrounds. If
we're going to use them to teach programming, it should be possible to
demonstrate encapsulation there.

Playgrounds support multiple files. Doesn't this alleviate this problem? Of course you can't model Swift's model in a single-file, but that's by-design.

Aside from that, as has been noted several times, the most common need is “current scope only”. It would be nice if that could actually be expressed in the language. There are often valid reasons to organize code such that more than one scope exists in the same file without a desire to share implementation details between the scopes. Right now there is a tension between code layout and the visibility semantics we actually desire and intend.

I disagree. You can pattern your code so that this appears to be the "most common need", but you can also pattern identical functioning code so that this feature doesn't even work.

For instance, I know in my code, this really isn't the "most common need". In fact, in nearly all of my code, local would be completely useless because I put the majority of my APIs in extensions. I like to model the data on the type definition and the APIs in extensions.

This proposal would make using extensions as a means of grouping functionality impossible:

struct Foo {
    local count: Int = 0
}

extension Foo {
    func hidden() { count += 1 } // error: count is not visible
}

So now we have to arbitrarily make `count` private, move `hidden()` into the `Foo` definition, or make `local` a whole lot more complicated.

If you design and write your code like you do in other languages, then ok, I can see a margin of usefulness from `local`.

Sure, if you use this method of organizing code `local` would be less useful and the need for file-level access would be much more common. I can see the benefits of organizing code this way; it is how code is organized in functional languages. When you follow this approach `local` would still be useful if you have helpers inside an extension. But you are right, it would not be the most common need.

I haven’t seen much Swift code actually organized this way in the wild. Maybe that will change, maybe not. But I stand by the assertion that they way most people are writing Swift today leads to “current scope only” is the most common need in practice.

Both `local` and `private` are useful. I would like to see both of them in the language.

-Matthew

···

On Jan 27, 2016, at 10:35 AM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 25, 2016, at 3:47 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Jan 27, 2016, at 7:44 AM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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

Ah, of course, you are right. Mixing both levels (file and class private) isn't possible with the current model, it's either one or the other.

Feeling a bit silly for not thinking of that myself and apologies to Ilya and you all for being a little thick-headed...

-Thorsten

···

Am 26.01.2016 um 05:40 schrieb Rob Mayoff via swift-evolution <swift-evolution@swift.org>:

On Mon, Jan 25, 2016 at 10:37 PM, Nate Birkholz via swift-evolution <swift-evolution@swift.org> wrote:
>> Note that moving a private class to its own file to make its privates more private does not work. Now I have to make the formerly-private class an internal class, so I'm not sending the first message anymore.
>
> Why do you have to make it internal then? I'm confused.

In Scheduler.swift, I have public (or internal) class Scheduler, and it uses private class JobRecord, also in Scheduler.swift.

I want to make some of JobRecord's members private to JobRecord. Right now, the only way to do that is to move JobRecord to a separate file, say JobRecord.swift, so that its privates become "more private" (since class JobRecord is the only thing in JobRecord.swift).

But in order for JobRecord to be visible to Scheduler, I now have to change "private class JobRecord" to "internal class JobRecord". The message-to-future-Rob that JobRecord is only intended for use by Scheduler.swift is lost (or at any rate its accuracy is no longer enforced by the compiler).

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