Protected Access


(Jon Hull) #1

The discussion of private/fileprivate reminded me of other access modifier issues that have been bugging me. I agree that the old system is better, but I am ambivalent about changing it back…

What I pretty much constantly want is an access modifier which lets me access something from an extension (which is potentially in a different file), but otherwise have it be private. The vast majority of my use of “fileprivate” is so that I can access internal properties/functions from an extension (which I am forced to place in the same file).

Access from subclasses is a larger discussion, but I run into this most often with Structs and their extensions.

The other pieces which seem to be missing are modifiers which allow finer grained control of how class methods are overridden and used.

It is a fairly common pattern in cocoa, for example, to have customization point methods which are designed to be overridden, but are not supposed to be called directly. Right now, this is enforced via documentation. One potential solution is to have a @noExternalCall attribute which says that it can only be called from the class/subclass/extensions… but if you think about it, this is basically another view of the first issue. If we could mark that method as only visible within the class/subclasses/extensions, then the behavior we want just falls out naturally. It can’t be called externally, because no one on the outside can see it.

I also occasionally run into this with protocols. I find that I have a property on the protocol which is needed for default implementations, but I really want to make it private with respect to the protocol (and its inheritors/extensions). That is, I want the implementor of the protocol to have visibility for that property, but not the caller of the protocol. Right now, I have to expose it to everyone (which clutters my external API), and then note in documentation not to call those properties.

Basically, I want to do the following:

  protocol P {
    hidden var a:Int
    var b:Int
  }

  extension P {
    var c:Int { return self.a + self.b}
  }

  struct A:P {
    private var a:Int = 5 // ‘A’ must implement, but it doesn’t have to expose it externally
    var b:Int = 2
  }

  struct B:P{
    var a:Int = 3 // ‘B’ chooses to expose, which is ok too
    var b:Int = 4
  }

  let ans = A().c // 7
  let ohNo = A().a // Error!

Basically ‘hidden’ in the protocol means that the implementor must implement the property, but it is not required to expose it to the world. I don’t really care whether that is spelled hidden, protected, or private, but I would use this fairly often.

Thanks,
Jon


(Callionica (Swift)) #2

For overridable, but not callable, you can use the technique outlined at
http://www.callionica.com/developer/#swift-protected
(give your method a parameter of a type that only the base class can create)

···

On Friday, October 7, 2016, Jonathan Hull via swift-evolution < swift-evolution@swift.org> wrote:

The discussion of private/fileprivate reminded me of other access modifier
issues that have been bugging me. I agree that the old system is better,
but I am ambivalent about changing it back…

What I pretty much constantly want is an access modifier which lets me
access something from an extension (which is potentially in a different
file), but otherwise have it be private. The vast majority of my use of
“fileprivate” is so that I can access internal properties/functions from an
extension (which I am forced to place in the same file).

Access from subclasses is a larger discussion, but I run into this most
often with Structs and their extensions.

The other pieces which seem to be missing are modifiers which allow finer
grained control of how class methods are overridden and used.

It is a fairly common pattern in cocoa, for example, to have customization
point methods which are designed to be overridden, but are not supposed to
be called directly. Right now, this is enforced via documentation. One
potential solution is to have a @noExternalCall attribute which says that
it can only be called from the class/subclass/extensions… but if you think
about it, this is basically another view of the first issue. If we could
mark that method as only visible within the class/subclasses/extensions,
then the behavior we want just falls out naturally. It can’t be called
externally, because no one on the outside can see it.

I also occasionally run into this with protocols. I find that I have a
property on the protocol which is needed for default implementations, but I
really want to make it private with respect to the protocol (and its
inheritors/extensions). That is, I want the implementor of the protocol to
have visibility for that property, but not the caller of the protocol.
Right now, I have to expose it to everyone (which clutters my external
API), and then note in documentation not to call those properties.

Basically, I want to do the following:

        protocol P {
                hidden var a:Int
                var b:Int
        }

        extension P {
                var c:Int { return self.a + self.b}
        }

        struct A:P {
                private var a:Int = 5 // ‘A’ must implement, but it
doesn’t have to expose it externally
                var b:Int = 2
        }

        struct B:P{
                var a:Int = 3 // ‘B’ chooses to expose, which is ok too
                var b:Int = 4
        }

        let ans = A().c // 7
        let ohNo = A().a // Error!

Basically ‘hidden’ in the protocol means that the implementor must
implement the property, but it is not required to expose it to the world.
I don’t really care whether that is spelled hidden, protected, or private,
but I would use this fairly often.

Thanks,
Jon

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


(Shawn Erickson) #3

I agree with and also feel access modifiers / controls are missing and the
ones we have may not be the best if you factor in these additional needs. I
also agree that I would prefer the discussion be more focused on this type
of thing. Thanks for capturing some of the things you have seen (I have
been meaning to do that myself but lacking in time and will do far).


(Xiaodi Wu) #4

Jon--earlier in the week, there was another thread which once against
raised the idea of internal or private protocol conformances; would that be
another way of addressing your use case here?

···

On Fri, Oct 7, 2016 at 6:36 PM, Callionica (Swift) via swift-evolution < swift-evolution@swift.org> wrote:

For overridable, but not callable, you can use the technique outlined at
http://www.callionica.com/developer/#swift-protected
(give your method a parameter of a type that only the base class can
create)

On Friday, October 7, 2016, Jonathan Hull via swift-evolution < > swift-evolution@swift.org> wrote:

The discussion of private/fileprivate reminded me of other access
modifier issues that have been bugging me. I agree that the old system is
better, but I am ambivalent about changing it back…

What I pretty much constantly want is an access modifier which lets me
access something from an extension (which is potentially in a different
file), but otherwise have it be private. The vast majority of my use of
“fileprivate” is so that I can access internal properties/functions from an
extension (which I am forced to place in the same file).

Access from subclasses is a larger discussion, but I run into this most
often with Structs and their extensions.

The other pieces which seem to be missing are modifiers which allow finer
grained control of how class methods are overridden and used.

It is a fairly common pattern in cocoa, for example, to have
customization point methods which are designed to be overridden, but are
not supposed to be called directly. Right now, this is enforced via
documentation. One potential solution is to have a @noExternalCall
attribute which says that it can only be called from the
class/subclass/extensions… but if you think about it, this is basically
another view of the first issue. If we could mark that method as only
visible within the class/subclasses/extensions, then the behavior we want
just falls out naturally. It can’t be called externally, because no one on
the outside can see it.

I also occasionally run into this with protocols. I find that I have a
property on the protocol which is needed for default implementations, but I
really want to make it private with respect to the protocol (and its
inheritors/extensions). That is, I want the implementor of the protocol to
have visibility for that property, but not the caller of the protocol.
Right now, I have to expose it to everyone (which clutters my external
API), and then note in documentation not to call those properties.

Basically, I want to do the following:

        protocol P {
                hidden var a:Int
                var b:Int
        }

        extension P {
                var c:Int { return self.a + self.b}
        }

        struct A:P {
                private var a:Int = 5 // ‘A’ must implement, but it
doesn’t have to expose it externally
                var b:Int = 2
        }

        struct B:P{
                var a:Int = 3 // ‘B’ chooses to expose, which is ok too
                var b:Int = 4
        }

        let ans = A().c // 7
        let ohNo = A().a // Error!

Basically ‘hidden’ in the protocol means that the implementor must
implement the property, but it is not required to expose it to the world.
I don’t really care whether that is spelled hidden, protected, or private,
but I would use this fairly often.

Thanks,
Jon

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

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


(Charles Srstka) #5

While that’s true, it’s pretty clearly a hack. Having this built into the language would not only be a lot more elegant, but could also prevent override-only methods from showing up in Xcode’s autocomplete.

Charles

···

On Oct 7, 2016, at 6:36 PM, Callionica (Swift) via swift-evolution <swift-evolution@swift.org> wrote:

For overridable, but not callable, you can use the technique outlined at http://www.callionica.com/developer/#swift-protected
(give your method a parameter of a type that only the base class can create)

On Friday, October 7, 2016, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
The discussion of private/fileprivate reminded me of other access modifier issues that have been bugging me. I agree that the old system is better, but I am ambivalent about changing it back…

What I pretty much constantly want is an access modifier which lets me access something from an extension (which is potentially in a different file), but otherwise have it be private. The vast majority of my use of “fileprivate” is so that I can access internal properties/functions from an extension (which I am forced to place in the same file).

Access from subclasses is a larger discussion, but I run into this most often with Structs and their extensions.

The other pieces which seem to be missing are modifiers which allow finer grained control of how class methods are overridden and used.

It is a fairly common pattern in cocoa, for example, to have customization point methods which are designed to be overridden, but are not supposed to be called directly. Right now, this is enforced via documentation. One potential solution is to have a @noExternalCall attribute which says that it can only be called from the class/subclass/extensions… but if you think about it, this is basically another view of the first issue. If we could mark that method as only visible within the class/subclasses/extensions, then the behavior we want just falls out naturally. It can’t be called externally, because no one on the outside can see it.

I also occasionally run into this with protocols. I find that I have a property on the protocol which is needed for default implementations, but I really want to make it private with respect to the protocol (and its inheritors/extensions). That is, I want the implementor of the protocol to have visibility for that property, but not the caller of the protocol. Right now, I have to expose it to everyone (which clutters my external API), and then note in documentation not to call those properties.

Basically, I want to do the following:

        protocol P {
                hidden var a:Int
                var b:Int
        }

        extension P {
                var c:Int { return self.a + self.b}
        }

        struct A:P {
                private var a:Int = 5 // ‘A’ must implement, but it doesn’t have to expose it externally
                var b:Int = 2
        }

        struct B:P{
                var a:Int = 3 // ‘B’ chooses to expose, which is ok too
                var b:Int = 4
        }

        let ans = A().c // 7
        let ohNo = A().a // Error!

Basically ‘hidden’ in the protocol means that the implementor must implement the property, but it is not required to expose it to the world. I don’t really care whether that is spelled hidden, protected, or private, but I would use this fairly often.

Thanks,
Jon

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