access control

I didn’t propose to remove or repurpose the existing “private” access modifier. Instead, I proposed an additional “local” modifier for real data encapsulation. I think that the current “private” modifier is misnamed. It would be much more concise to call it “file internal” or something similar, but it looks like it’s too late to change this now. Both “private” and “local” are useful. One doesn’t have to exclude the other.

Yes, it does trade formalism for convenience, but I believe that the tradeoff is reasonable.

Both can and should exist in the language. No need for tradeoffs.

You already need to maintain some degree of discipline when writing code (you can’t make the compiler to enforce all conventions for you)

In every other respect, Swift compiler tries to help, except this one. The strong type system and type inference are a big deal. This is a big deal for the same reason.

I don’t think that its such a big deal to ask people to be careful when modifying a file with a pre-existing type implementation.

An intent, clearly spelled out in the property or function declaration, that is enforceable by the compiler will eliminate human errors much more reliably than convention and attempts to be careful. We have ARC and destructors that are automatically called for the same reason.

In the end, your argumentation mainly applies to the case when you have multiple type implementation in the same file. Which is bad style in the first place.

This is a matter or opinion. Earlier:

If one class and one extension per file become a requirement,
then private will have the same semantics as in C++. It will also
become very inconvenient to write code because even a small extension
with 1 method that can fit on one line will require a separate file.

Which is why this rule “one class per file” is not there.

Once you embrace idea that all declarations in a single file are closely interdependent (this way or another), file-based access control stops being an issue as you present it.

It will still be an issue because there is no way to express the author’s intent on whether something is truly private or can be safely shared with closely related code.

···

On Jan 25, 2016, at 9:04 AM, Taras Zakharko <taras.zakharko@uzh.ch> wrote:

That is true of course, but explicitly modelling complex dependency relationships between scopes can be tedious. If you make private truly private, then you also need concepts such a friends and many some others in order to write efficient code. File- and module-based access offers a decent compromise by allowing you to put interdependent implementations into a single file. Personally, I think that this is an elegant and reasonable solution. Yes, it does trade formalism for convenience, but I believe that the tradeoff is reasonable. You already need to maintain some degree of discipline when writing code (you can’t make the compiler to enforce all conventions for you), and I don’t think that its such a big deal to ask people to be careful when modifying a file with a pre-existing type implementation. In the end, your argumentation mainly applies to the case when you have multiple type implementation in the same file. Which is bad style in the first place. Once you embrace idea that all declarations in a single file are closely interdependent (this way or another), file-based access control stops being an issue as you present it.

Best,

Taras

On 25 Jan 2016, at 14:45, Ilya Belenkiy <ilya.belenkiy@gmail.com <mailto:ilya.belenkiy@gmail.com>> wrote:

Formal means enforceable by the compiler. File based access control is useful as well but not as a substitute for real data encapsulation.

On Mon, Jan 25, 2016 at 8:13 AM Taras Zakharko <taras.zakharko@googlemail.com <mailto:taras.zakharko@googlemail.com>> wrote:
I disagree with Ilya on his stance on ‘private’. I do understand the argumentation, but the reasoning seems overly formal to me and the classical solution (private visible only within the class) also comes with a number of drawbacks that result in things like friends declarations in C++. It is nice to have relationships between entities explicit, but one can go overboard with the rigidity.

However, I also strongly agree with Thorsten that a subclass (but not public) visible modifier has a lot of uses. I would prefer to have four levels of access:

private (file scope)
internal (module scope)
protected (subclass scope)
public

Best,

Taras

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

Am 23.01.2016 um 16:56 schrieb Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

I hope that access control can be revisited. It is the number one complaint about Swift that I hear from experienced developers. The current solution came as a complete surprise to every ObjC developer I've talked to. The natural expectation was that a strong access control system would be part of a strong type system. I already submitted a pull request with a proposal for this after a lengthy discussion here, but so far it was ignored. I hope that this can be revisited. Even if most people who responded earlier in this list decided that they were happy with the current state, it represents a tiny fraction of people using the language, and at least all the people I talked to strongly disagree but just aren’t on the list.

Right now access control is file based and not API based. This is much easier to implement but useless to express that certain elements of a class are implementation details that are not meant to be used anywhere else (someone can add more code to the same file and get access to the implementation details without modifying the class).

I think the file based approach for `private` has advantages because it allows putting several things that have to know each other deeply into the same file (C++ would use friend access for that).

It’s also impossible to hide APIs that are meant only for customization points of subclasses.

Here I agree. What I am really missing is the ability to declare something „protected“ in a protocol (or class) which is not part of the public API but which I then can use in its default implementation but which has to be provided by implementors of the protocol.

Example (shortened and simplified to just show the relevant parts):

public protocol StandardGraphTraversal {
  // push() and pop() are implementation details and not part of the API
  protected func push(vertex: Vertex)
  protected func pop() -> Vertex?

  public func next() -> Vertex?
}

public extension StandardGraphTraversal {

  // leaving out things like visitor callbacks and coloring the visited vertices
  public func next() -> Vertex? {
    guard let source = pop() else { // using pop() here
      return nil
    }
    for target in graph.neighborsOf(source) {
      if shouldFollowVertex(target) {
        push(vertex) // using push() here
      }
    }
  }
}

// supplying the implementation detail: using a queue results in breadth first traversal
public struct BreadthFirstTraversal : StandardGraphTraversal {
  var queue: Queue<Vertex> = Queue()

  protected func push(vertex: Vertex) { return queue.push(vertex) }
  protected func pop() -> Vertex? { return queue.pop() }
}

// supplying the implementation detail: using a stack results in depth first traversal
public struct DepthFirstTraversal : StandardGraphTraversal {
  var stack: Stack<Vertex> = Stack()

  protected func push(vertex: Vertex) { return stack.push(vertex) }
  protected func pop() -> Vertex? { return stack.pop() }
}
  
Currently I cannot express that in Swift and have to make push() and pop() public :-(

(Allowing `internal` in public protocols would be sufficient in my example but would not help in more general cases where the implementors would have to be provided in another module by the framework user).

.NET has a good solution that respects the OOP terminology and deals with accessibility in modules and at the API level:
Access Modifiers - C# Reference - C# | Microsoft Learn

`public` and `internal` seem to be quite the same as in Swift.
`private` is based on the type instead of the file. I think Swift’s file based `private` is better because it allows to express the same by putting a type into its file alone and allows to create strongly interdependent types by putting them together into the same file.
`protected` is what I’m missing as well
`protected internal` seems to be the union of `protected` and `internal`. I think that is not needed and is probably there to allow testing for which Swift has a nicer solution with @testable imports.

In short the only thing which is missing IMO is `protected`.

-Thorsten

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

Oh, then I apologise. I got the wrong impression and/or was inattentive. In principle, I see no issue with adding a new access modifier as you suggest. I don’t think that I personally will use it, but some people could find it useful.

— Taras

···

On 25 Jan 2016, at 16:12, Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

I didn’t propose to remove or repurpose the existing “private” access modifier. Instead, I proposed an additional “local” modifier for real data encapsulation. I think that the current “private” modifier is misnamed. It would be much more concise to call it “file internal” or something similar, but it looks like it’s too late to change this now. Both “private” and “local” are useful. One doesn’t have to exclude the other.

I didn’t propose to remove or repurpose the existing “private” access modifier. Instead, I proposed an additional “local” modifier for real data encapsulation. I think that the current “private” modifier is misnamed. It would be much more concise to call it “file internal” or something similar, but it looks like it’s too late to change this now. Both “private” and “local” are useful. One doesn’t have to exclude the other.

Yes, it does trade formalism for convenience, but I believe that the tradeoff is reasonable.

Both can and should exist in the language. No need for tradeoffs.

I don’t see much of a tradeoff: if you want class private just put nothing else in the file.

You already need to maintain some degree of discipline when writing code (you can’t make the compiler to enforce all conventions for you)

In every other respect, Swift compiler tries to help, except this one. The strong type system and type inference are a big deal. This is a big deal for the same reason.

I don’t understand: the compiler checks whether you have access to a member, so it certainly does help, doesn’t it?

Once you embrace idea that all declarations in a single file are closely interdependent (this way or another), file-based access control stops being an issue as you present it.

It will still be an issue because there is no way to express the author’s intent on whether something is truly private or can be safely shared with closely related code.

If you edit the same file you are in effect the class’s author and therefore should know the intent (or be able to derive it). When I’m editing a Java class (possibly written by someone else) I also have to check whether I can safely use a private method or whether I’m breaking the inner workings of the class by my changes. No real difference there.

-Thorsten

···

Am 25.01.2016 um 16:12 schrieb Ilya Belenkiy <ilya.belenkiy@gmail.com>:

Thanks for sharing that.

It seems like the proposal would be stronger with some specific code examples of problems that can arise with `private` that are ameliorated with the introduction of `local`. I get the basic idea: with `private` I have to understand all the invariants in the file while with `local` I only need to understand the invariants within the lexical scope. However, I'm having trouble understanding the situation where those are sufficiently different to justify increasing the complexity of the language. (If you were proposing replacing `private` with `local`, then the complexity would be the same. Of course, in that case, you'd need to justify removing the level of access that allows extensions to access private members.) I may just be failing to understand. If so, a sufficiently detailed example would help, I think.

Secondly, in some languages, private members can only be accessed on self instances. Is your intention that local members can only be accessed thusly. That is, would the following be allowed:

struct Foo {
  local var bar: String
  // ...
  mutating func concatBar(otherFoo: Foo) {
    let othersBar = otherFoo.bar // legal?
    bar = bar + othersBar
  }
}

More generally, different languages have provided a wide variation in the specificity of their access control mechanisms. If `local` is only about static scope (i.e., the example above is legal), then do we need a mechanism for restricting to self-only access? Where is the appropriate floor on access restrictions? Why isn't a single file the appropriate floor?

Cheers,

Curt

···

On Jan 23, 2016, at 6:37 PM, Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

Here is a link to the pull request:

proposal for scoped access level by ilyathewhite · Pull Request #64 · apple/swift-evolution · GitHub

On Jan 23, 2016, at 9:23 PM, Curt Clifton <curt@omnigroup.com> wrote:

It might aid the discussion if you provided a link to your proposal. I'm assuming it includes examples of problems that your proposed changes solve. I'd be interested in seeing those.

Cheers,

Curt
-------------------------
Curt Clifton, PhD
Software Developer
The Omni Group
www.curtclifton.net

On Jan 23, 2016, at 6:17 PM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

Yes, but with an API based access control,

I don't know what that term means, sorry.

I had to come up with this term to distinguish it from a file based access control. In API based access control, visibility of anything is tied to the declaration instead of the file it is in. It’s the model that C++ and C# ( and I am sure many others) use. In file based access control, visibility of anything is tied to the file it is in and has little to do with the class API itself. It’s the model that Swift currently follows.

anyone modifying / extending the class can instantly see the author’s
intent from the API declaration,

I don't see how that's different from what we have in Swift. Private
APIs are the ones you don't want anyone to touch because they can break
your invariants.

In Swift, any additional code in the same source file can use the APIs declared private and break your invariants. The semantic meaning of private is not “use only inside the class” but “use only inside this file”. It is currently impossible to express “use only inside the class” semantics.

Seeing the keyword “private” isn't enough for you in Swift, but it is in
C++? Why?

Because in Swift, private means “use only inside this file” and not “use only inside this class / scope”. In C++ private means “use only inside this class”. Moreover, C++ puts a special emphasis on this — variables are private inside the class unless the code specifically says otherwise.

Defining one type per file is usually a good practice anyway.

This really depends on the context. There is value in keeping similar concepts / implementations in the same file. If one class and one extension per file become a requirement, then private will have the same semantics as in C++. It will also become very inconvenient to write code because even a small extension with 1 method that can fit on one line will require a separate file.

Without prohibiting class extensions from being made in the same file
where the class is defined—a capability we want to keep available to
class authors—that will always be the case.

It doesn’t have to be. My proposal (still a pull request) provides a way to explicitly declare a function or a property to be private to the scope where it is defined. So extensions and subclasses declared in the same file cannot access it and break the invariant. If it’s applied to both class definitions and extensions, it’s very consistent and provides an explicit declaration of intent that can (and should) be enforced by the compiler.

Therefore, you have the
same scenario as in C++: anyone who modifies the file where a class is
defined might be violating its invariants. It's just that in C++ the
violator has to write code between a particular set of braces. When
reviewing diffs it's very common not to have enough context to see those
braces anyway.

This is a crucial distinction. That particular set of braces defines a scope which acts as a black box and hides the implementation details. Anything outside the scope cannot damage the internal state, and the compiler *enforces* it. In Swift, the compiler only enforces that the API is not visible from another file because the language has no way to express “this should be visible only in the scope to hide implementation details”. The only exception to that are functions inside other functions and local variables — right now this is the only way to completely hide implementation details, but it’s very limited.

My main 2 points are that it’s impossible to express the intent of a truly local access level to hide implementation details, and because of that, the compiler cannot enforce this intent.

When
reviewing diffs it's very common not to have enough context to see those
braces anyway.

This depends on how thoroughly the code is reviewed. But the main point there is that when you find out, you know that whoever worked around a private API did so knowing that he was introducing a hack. Because Swift has no way of expressing “this is private to the class, not just file it’s in”, someone may not know and make a mistake, and the compiler cannot catch it. My proposal makes the intent expressible in the language and enforceable by the compiler.

Not at all in the same way. In C++, you can't add methods to a class
outside the file where it's declared unless there's some really horrible
preprocessor stuff going on, and even then the class author would have
had to explicitly left that door open for you.

True, but my proposal deals with extensions the same way it does with class definitions — it provides a way to hide implementation details in a scope (whether it be a class definition or an extension scope) and make them invisible to everything else including extensions or other extensions or anything else in the same file. It provides a way to express the intent in the language and enforce it by the compiler.

On Jan 23, 2016, at 5:43 PM, Dave Abrahams <dabrahams@apple.com> wrote:

on Sat Jan 23 2016, Ilya Belenkiy <ilya.belenkiy-AT-gmail.com> wrote:

Anyone who can "add more code to the same file" can just as easily modify/extend the class.

Yes, but with an API based access control,

I don't know what that term means, sorry.

anyone modifying / extending the class can instantly see the author’s
intent from the API declaration,

I don't see how that's different from what we have in Swift. Private
APIs are the ones you don't want anyone to touch because they can break
your invariants.

and the compiler can prevent *accidental* misuse. Deliberate misuse
cannot be stopped no matter what access control is in place (as long
as the coder can modify the code in the module). But at least with an
API based access control, a deliberate misuse is very easy to spot
when debugging / reviewing the code. With a file based access control,
the only way to tell if an API is really private or can be safely used
anywhere in the same file is to read the comments / source code.

Seeing the keyword “private” isn't enough for you in Swift, but it is in
C++? Why?

And it’s much easier to miss in maintenance, debugging, or code
reviews. The only way to make it obvious in the current model is to
adopt a convention like _ in front of methods.

The only reason we're doing that in the standard library is that we're
currently forced to make some implementation details formally public,
and we can't use “private” because <reasons>. If it weren't for these
limitations, we'd be very happy with “private.” Defining one type per
file is usually a good practice anyway.

There's nothing about extending a class that ought to raise a red
flag in Swift, because it's perfectly legit to do so and use only
the class' public APIs.

Unless the programmer extends a class in the same file. Then he can
call anything marked private, and it’s impossible to tell without
reading the code whether it violates the class invariants.

Without prohibiting class extensions from being made in the same file
where the class is defined—a capability we want to keep available to
class authors—that will always be the case. Therefore, you have the
same scenario as in C++: anyone who modifies the file where a class is
defined might be violating its invariants. It's just that in C++ the
violator has to write code between a particular set of braces. When
reviewing diffs it's very common not to have enough context to see those
braces anyway.

There is no way to express this in Swift today. My proposal for local
/ scoped access control would solve this.

we didn't do file-level access control because it was easier; we
did it because we thought it was a better model for Swift, where
types are liberally open for extension.

That’s what I assumed until I saw someone say it in this list when
someone else raised a similar concern. Types in C++ and C# are also
liberally open for extension,

Not at all in the same way. In C++, you can't add methods to a class
outside the file where it's declared unless there's some really horrible
preprocessor stuff going on, and even then the class author would have
had to explicitly left that door open for you.

--
-Dave

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

The main idea is that “local” makes the author’s intent clear (the function or property should not be visible outside the scope) and it’s enforceable by the compiler and protects against accidental misuse. It also makes deliberate misuse easier to spot because it would require changes to the function or property declaration.

It is different from private in that you can add code to the same file and access anything marked as private and break things by calling something that was not supposed to be used directly. With local, you are forced to modify the function declaration, and you know that you are using the function or a property that was specifically hidden by the author. With private, you can never know if it can or cannot be called in the same file without the danger of breaking class invariant.

I think that lexical scope (type based) access would be enough. I wouldn’t want to require self (C++ and C# model) because it’s about the type, not the instance. But if this was the only way to get this accepted, I’d support that. It would be much better than nothing.

Where is the appropriate floor on access restrictions? Why isn't a single file the appropriate floor?

I think that it’s scope. It’s the smallest subdivision that can exit, and it provides a way to specify a public API for a class. Private as it is today does not express public / private API for a class. It only expresses access inside the same compilation unit, which is different.

···

On Jan 23, 2016, at 10:50 PM, Curt Clifton <curt@omnigroup.com> wrote:

Thanks for sharing that.

It seems like the proposal would be stronger with some specific code examples of problems that can arise with `private` that are ameliorated with the introduction of `local`. I get the basic idea: with `private` I have to understand all the invariants in the file while with `local` I only need to understand the invariants within the lexical scope. However, I'm having trouble understanding the situation where those are sufficiently different to justify increasing the complexity of the language. (If you were proposing replacing `private` with `local`, then the complexity would be the same. Of course, in that case, you'd need to justify removing the level of access that allows extensions to access private members.) I may just be failing to understand. If so, a sufficiently detailed example would help, I think.

Secondly, in some languages, private members can only be accessed on self instances. Is your intention that local members can only be accessed thusly. That is, would the following be allowed:

struct Foo {
local var bar: String
// ...
mutating func concatBar(otherFoo: Foo) {
   let othersBar = otherFoo.bar // legal?
   bar = bar + othersBar
}
}

More generally, different languages have provided a wide variation in the specificity of their access control mechanisms. If `local` is only about static scope (i.e., the example above is legal), then do we need a mechanism for restricting to self-only access? Where is the appropriate floor on access restrictions? Why isn't a single file the appropriate floor?

Cheers,

Curt

On Jan 23, 2016, at 6:37 PM, Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

Here is a link to the pull request:

proposal for scoped access level by ilyathewhite · Pull Request #64 · apple/swift-evolution · GitHub

On Jan 23, 2016, at 9:23 PM, Curt Clifton <curt@omnigroup.com> wrote:

It might aid the discussion if you provided a link to your proposal. I'm assuming it includes examples of problems that your proposed changes solve. I'd be interested in seeing those.

Cheers,

Curt
-------------------------
Curt Clifton, PhD
Software Developer
The Omni Group
www.curtclifton.net

On Jan 23, 2016, at 6:17 PM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

Yes, but with an API based access control,

I don't know what that term means, sorry.

I had to come up with this term to distinguish it from a file based access control. In API based access control, visibility of anything is tied to the declaration instead of the file it is in. It’s the model that C++ and C# ( and I am sure many others) use. In file based access control, visibility of anything is tied to the file it is in and has little to do with the class API itself. It’s the model that Swift currently follows.

anyone modifying / extending the class can instantly see the author’s
intent from the API declaration,

I don't see how that's different from what we have in Swift. Private
APIs are the ones you don't want anyone to touch because they can break
your invariants.

In Swift, any additional code in the same source file can use the APIs declared private and break your invariants. The semantic meaning of private is not “use only inside the class” but “use only inside this file”. It is currently impossible to express “use only inside the class” semantics.

Seeing the keyword “private” isn't enough for you in Swift, but it is in
C++? Why?

Because in Swift, private means “use only inside this file” and not “use only inside this class / scope”. In C++ private means “use only inside this class”. Moreover, C++ puts a special emphasis on this — variables are private inside the class unless the code specifically says otherwise.

Defining one type per file is usually a good practice anyway.

This really depends on the context. There is value in keeping similar concepts / implementations in the same file. If one class and one extension per file become a requirement, then private will have the same semantics as in C++. It will also become very inconvenient to write code because even a small extension with 1 method that can fit on one line will require a separate file.

Without prohibiting class extensions from being made in the same file
where the class is defined—a capability we want to keep available to
class authors—that will always be the case.

It doesn’t have to be. My proposal (still a pull request) provides a way to explicitly declare a function or a property to be private to the scope where it is defined. So extensions and subclasses declared in the same file cannot access it and break the invariant. If it’s applied to both class definitions and extensions, it’s very consistent and provides an explicit declaration of intent that can (and should) be enforced by the compiler.

Therefore, you have the
same scenario as in C++: anyone who modifies the file where a class is
defined might be violating its invariants. It's just that in C++ the
violator has to write code between a particular set of braces. When
reviewing diffs it's very common not to have enough context to see those
braces anyway.

This is a crucial distinction. That particular set of braces defines a scope which acts as a black box and hides the implementation details. Anything outside the scope cannot damage the internal state, and the compiler *enforces* it. In Swift, the compiler only enforces that the API is not visible from another file because the language has no way to express “this should be visible only in the scope to hide implementation details”. The only exception to that are functions inside other functions and local variables — right now this is the only way to completely hide implementation details, but it’s very limited.

My main 2 points are that it’s impossible to express the intent of a truly local access level to hide implementation details, and because of that, the compiler cannot enforce this intent.

When
reviewing diffs it's very common not to have enough context to see those
braces anyway.

This depends on how thoroughly the code is reviewed. But the main point there is that when you find out, you know that whoever worked around a private API did so knowing that he was introducing a hack. Because Swift has no way of expressing “this is private to the class, not just file it’s in”, someone may not know and make a mistake, and the compiler cannot catch it. My proposal makes the intent expressible in the language and enforceable by the compiler.

Not at all in the same way. In C++, you can't add methods to a class
outside the file where it's declared unless there's some really horrible
preprocessor stuff going on, and even then the class author would have
had to explicitly left that door open for you.

True, but my proposal deals with extensions the same way it does with class definitions — it provides a way to hide implementation details in a scope (whether it be a class definition or an extension scope) and make them invisible to everything else including extensions or other extensions or anything else in the same file. It provides a way to express the intent in the language and enforce it by the compiler.

On Jan 23, 2016, at 5:43 PM, Dave Abrahams <dabrahams@apple.com> wrote:

on Sat Jan 23 2016, Ilya Belenkiy <ilya.belenkiy-AT-gmail.com> wrote:

Anyone who can "add more code to the same file" can just as easily modify/extend the class.

Yes, but with an API based access control,

I don't know what that term means, sorry.

anyone modifying / extending the class can instantly see the author’s
intent from the API declaration,

I don't see how that's different from what we have in Swift. Private
APIs are the ones you don't want anyone to touch because they can break
your invariants.

and the compiler can prevent *accidental* misuse. Deliberate misuse
cannot be stopped no matter what access control is in place (as long
as the coder can modify the code in the module). But at least with an
API based access control, a deliberate misuse is very easy to spot
when debugging / reviewing the code. With a file based access control,
the only way to tell if an API is really private or can be safely used
anywhere in the same file is to read the comments / source code.

Seeing the keyword “private” isn't enough for you in Swift, but it is in
C++? Why?

And it’s much easier to miss in maintenance, debugging, or code
reviews. The only way to make it obvious in the current model is to
adopt a convention like _ in front of methods.

The only reason we're doing that in the standard library is that we're
currently forced to make some implementation details formally public,
and we can't use “private” because <reasons>. If it weren't for these
limitations, we'd be very happy with “private.” Defining one type per
file is usually a good practice anyway.

There's nothing about extending a class that ought to raise a red
flag in Swift, because it's perfectly legit to do so and use only
the class' public APIs.

Unless the programmer extends a class in the same file. Then he can
call anything marked private, and it’s impossible to tell without
reading the code whether it violates the class invariants.

Without prohibiting class extensions from being made in the same file
where the class is defined—a capability we want to keep available to
class authors—that will always be the case. Therefore, you have the
same scenario as in C++: anyone who modifies the file where a class is
defined might be violating its invariants. It's just that in C++ the
violator has to write code between a particular set of braces. When
reviewing diffs it's very common not to have enough context to see those
braces anyway.

There is no way to express this in Swift today. My proposal for local
/ scoped access control would solve this.

we didn't do file-level access control because it was easier; we
did it because we thought it was a better model for Swift, where
types are liberally open for extension.

That’s what I assumed until I saw someone say it in this list when
someone else raised a similar concern. Types in C++ and C# are also
liberally open for extension,

Not at all in the same way. In C++, you can't add methods to a class
outside the file where it's declared unless there's some really horrible
preprocessor stuff going on, and even then the class author would have
had to explicitly left that door open for you.

--
-Dave

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

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?

In addition, it is not possible to completely hide state/implementation details in any language (at least that I have experience with). Java, for instance, will let me use the security manager and RTTI to modify private values, and even has JNI code to modify final values as well (this is how System.out works). There are projects that fundamentally depend on being able to access private fields, such as Spring, partly because the Java standard library tells them to (@Injectable).

Even with a “perfect” language mechanism, consumers of the binary will still patch it if they need to in order to get the functionality they want.

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. I feel comfortable saying to my team members that you have to justify adding code next to a class in the same way you would need to justify changing the implementation of that class. The difference between ‘local’ and ‘private’ access is a copy/paste of a function from an extension into the class body within the same file.

-DW

···

On Jan 24, 2016, at 1:15 PM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

I think it's possible to believe that your feature would be useful
without also believing there's something fundamentally wrong with the
current model, and your arguments make it sound to me like you think
you're getting a lot more certainty from C++'s "private" than you
actually are.

Data encapsulation is a cornerstone of object oriented programming. Swift has classes, and yet it is impossible to completely hide state / implementation details inside the class. Moreover, it’s impossible to express that something is intended to be completely hidden. Since such a fundamental idea is not supported, there is something fundamentally wrong with the current model. Swift is already a great language, and this issue aside, it’s by far the best language I’ve used. In all other areas Swift does a great job to help the programmer write correct code. This is one weird and very noticeable deviation.

I don’t see much of a tradeoff: if you want class private just put nothing else in the file.

It’s a convention that is not enforced by the compiler. Anyone can break it, accidentally or deliberately.

I don’t understand: the compiler checks whether you have access to a member, so it certainly does help, doesn’t it?

Not if you are in the same file. If you are, you can access anything.

If you edit the same file you are in effect the class’s author

Not necessarily.

and therefore should know the intent (or be able to derive it).

but if the API is marked properly, you don’t need derive anything — just look at the declaration. Also, with “local” the compiler catches a mistake while with “private” it is possible to make it. Why do this manually with a huge potential for human error when the compiler can enforce it for you?

When I’m editing a Java class (possibly written by someone else) I also have to check whether I can safely use a private method or whether I’m breaking the inner workings of the class by my changes. No real difference there.

Because in Java, the compiler enforces one class per file. So you in Java you *are* changing the class itself. If Swift enforced one class per file and one extension per file, there would be no difference, but nobody wants that because it would be very inconvenient.

···

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

Am 25.01.2016 um 16:12 schrieb Ilya Belenkiy <ilya.belenkiy@gmail.com>:

I didn’t propose to remove or repurpose the existing “private” access modifier. Instead, I proposed an additional “local” modifier for real data encapsulation. I think that the current “private” modifier is misnamed. It would be much more concise to call it “file internal” or something similar, but it looks like it’s too late to change this now. Both “private” and “local” are useful. One doesn’t have to exclude the other.

Yes, it does trade formalism for convenience, but I believe that the tradeoff is reasonable.

Both can and should exist in the language. No need for tradeoffs.

I don’t see much of a tradeoff: if you want class private just put nothing else in the file.

You already need to maintain some degree of discipline when writing code (you can’t make the compiler to enforce all conventions for you)

In every other respect, Swift compiler tries to help, except this one. The strong type system and type inference are a big deal. This is a big deal for the same reason.

I don’t understand: the compiler checks whether you have access to a member, so it certainly does help, doesn’t it?

Once you embrace idea that all declarations in a single file are closely interdependent (this way or another), file-based access control stops being an issue as you present it.

It will still be an issue because there is no way to express the author’s intent on whether something is truly private or can be safely shared with closely related code.

If you edit the same file you are in effect the class’s author and therefore should know the intent (or be able to derive it). When I’m editing a Java class (possibly written by someone else) I also have to check whether I can safely use a private method or whether I’m breaking the inner workings of the class by my changes. No real difference there.

-Thorsten

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 don’t think that there is a trade-off here. My proposal doesn’t break anything. It only adds one more modifier which is not inconsistent with the existing access control. I also think that it will be easy to implement for anyone who is familiar with the code.

In addition, it is not possible to completely hide state/implementation details in any language (at least that I have experience with).

It’s the same argument as the worth of having a strong type system. In C++, you can reinterpret any pointer any way you want, but it still has a very strong type system and a very strong access control. The intent is to catch *accidental* mistakes, not a deliberate misuse. The compiler is much better at this than any convention.

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.

I feel comfortable saying to my team members that you have to justify adding code next to a class in the same way you would need to justify changing the implementation of that class. The difference between ‘local’ and ‘private’ access is a copy/paste of a function from an extension into the class body within the same file.

It’s more than just extensions. Right now *anything* in the same file can access the class internal state. It’s a deliberate choice, and having this level of access control may be useful. “local” would provide the currently missing real data encapsulation from anything outside the class (including its extensions).

···

On Jan 24, 2016, at 9:54 PM, David Waite <david@alkaline-solutions.com> wrote:

On Jan 24, 2016, at 1:15 PM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

I think it's possible to believe that your feature would be useful
without also believing there's something fundamentally wrong with the
current model, and your arguments make it sound to me like you think
you're getting a lot more certainty from C++'s "private" than you
actually are.

Data encapsulation is a cornerstone of object oriented programming. Swift has classes, and yet it is impossible to completely hide state / implementation details inside the class. Moreover, it’s impossible to express that something is intended to be completely hidden. Since such a fundamental idea is not supported, there is something fundamentally wrong with the current model. Swift is already a great language, and this issue aside, it’s by far the best language I’ve used. In all other areas Swift does a great job to help the programmer write correct code. This is one weird and very noticeable deviation.

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?

In addition, it is not possible to completely hide state/implementation details in any language (at least that I have experience with). Java, for instance, will let me use the security manager and RTTI to modify private values, and even has JNI code to modify final values as well (this is how System.out works). There are projects that fundamentally depend on being able to access private fields, such as Spring, partly because the Java standard library tells them to (@Injectable).

Even with a “perfect” language mechanism, consumers of the binary will still patch it if they need to in order to get the functionality they want.

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. I feel comfortable saying to my team members that you have to justify adding code next to a class in the same way you would need to justify changing the implementation of that class. The difference between ‘local’ and ‘private’ access is a copy/paste of a function from an extension into the class body within the same file.

-DW

IIya: Private access on file is just fine. I do not understand why you are
so much against it. Just stop for 10 minutes and think about it...
Ondrej Barina

···

On Mon, Jan 25, 2016 at 3:54 AM, David Waite via swift-evolution < swift-evolution@swift.org> wrote:

> On Jan 24, 2016, at 1:15 PM, Ilya Belenkiy via swift-evolution < > swift-evolution@swift.org> wrote:
>
>> I think it's possible to believe that your feature would be useful
>> without also believing there's something fundamentally wrong with the
>> current model, and your arguments make it sound to me like you think
>> you're getting a lot more certainty from C++'s "private" than you
>> actually are.
>
>
> Data encapsulation is a cornerstone of object oriented programming.
Swift has classes, and yet it is impossible to completely hide state /
implementation details inside the class. Moreover, it’s impossible to
express that something is intended to be completely hidden. Since such a
fundamental idea is not supported, there is something fundamentally wrong
with the current model. Swift is already a great language, and this issue
aside, it’s by far the best language I’ve used. In all other areas Swift
does a great job to help the programmer write correct code. This is one
weird and very noticeable deviation.

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?

In addition, it is not possible to completely hide state/implementation
details in any language (at least that I have experience with). Java, for
instance, will let me use the security manager and RTTI to modify private
values, and even has JNI code to modify final values as well (this is how
System.out works). There are projects that fundamentally depend on being
able to access private fields, such as Spring, partly because the Java
standard library tells them to (@Injectable).

Even with a “perfect” language mechanism, consumers of the binary will
still patch it if they need to in order to get the functionality they want.

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. I feel comfortable saying to
my team members that you have to justify adding code next to a class in the
same way you would need to justify changing the implementation of that
class. The difference between ‘local’ and ‘private’ access is a copy/paste
of a function from an extension into the class body within the same file.

-DW

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

I do not understand why you are so much against it

Data encapsulation is a cornerstone of object oriented programming. Swift has classes, and yet it is impossible to completely hide state / implementation details inside the class. Moreover, it’s impossible to express that something is intended to be completely hidden. Since such a fundamental idea is not supported, there is something fundamentally wrong with the current model.

Just stop for 10 minutes and think about it…

···

On Jan 25, 2016, at 4:21 AM, Ondrej Barina <obarina@gmail.com> wrote:

IIya: Private access on file is just fine. I do not understand why you are so much against it. Just stop for 10 minutes and think about it...
Ondrej Barina

On Mon, Jan 25, 2016 at 3:54 AM, David Waite via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

> On Jan 24, 2016, at 1:15 PM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>> I think it's possible to believe that your feature would be useful
>> without also believing there's something fundamentally wrong with the
>> current model, and your arguments make it sound to me like you think
>> you're getting a lot more certainty from C++'s "private" than you
>> actually are.
>
>
> Data encapsulation is a cornerstone of object oriented programming. Swift has classes, and yet it is impossible to completely hide state / implementation details inside the class. Moreover, it’s impossible to express that something is intended to be completely hidden. Since such a fundamental idea is not supported, there is something fundamentally wrong with the current model. Swift is already a great language, and this issue aside, it’s by far the best language I’ve used. In all other areas Swift does a great job to help the programmer write correct code. This is one weird and very noticeable deviation.

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?

In addition, it is not possible to completely hide state/implementation details in any language (at least that I have experience with). Java, for instance, will let me use the security manager and RTTI to modify private values, and even has JNI code to modify final values as well (this is how System.out works). There are projects that fundamentally depend on being able to access private fields, such as Spring, partly because the Java standard library tells them to (@Injectable).

Even with a “perfect” language mechanism, consumers of the binary will still patch it if they need to in order to get the functionality they want.

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. I feel comfortable saying to my team members that you have to justify adding code next to a class in the same way you would need to justify changing the implementation of that class. The difference between ‘local’ and ‘private’ access is a copy/paste of a function from an extension into the class body within the same file.

-DW

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

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

···

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

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

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

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

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

That is difficult to disagree with. Similar points made for static typing can be made for this.

···

Sent from my iPhone

On 25 Jan 2016, at 19:33, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

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

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

···

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

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

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.

···

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.

--
-Dave

Let's please keep "protected" on a separate thread. Adding "protected" and adding "local" are pretty much completely orthogonal.

Jordan

···

On Jan 25, 2016, at 14:19, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

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

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