[Discussion] Protocol member deprecations


(Charlie Monroe) #1

I am currently working on updating some protocol APIs in a framework that's shared among several of my projects. The issue here is that the protocol has an extension with default implementation. For example:

protocol Foo {
    func doSomethingWithArray(_ arr: [String])
}

extension Foo {
    func doSomethingWithArray(_ arr: [String]) {
        print(arr)
    }
}

With this you can easily write

struct Bar: Foo { }

The issue comes when the struct actually implements the method and you decide to rename it in the protocol:

struct Bar: Foo {
    func doSomethingWithArray(_ arr: [String]) {
        fatalError()
    }
}

protocol Foo {
    func doSomething(with arr: [String])
}

extension Foo {
    func doSomething(with arr: [String]) {
        print(arr)
    }
}

The code still compiles, yet the behavior of the app changes incredibly. There is no way (to my knowledge) of marking some protocol members as deprecated. I've tried the "obvious" solution:

extension Foo {
    @available(*, deprecated, renamed: "doSomething(with:)")
    func doSomethingWithArray(_ arr: [String]) {
        self.doSomething(with: arr)
    }
}

But unfortunately, this doesn't emit any warning on the Bar structure. I personally believe that this is a major flaw, given that Swift is being claimed as Protocol-Oriented language, there is no way to declare that a protocol method is deprecated/renamed. Mainly with protocols with default implementations (or in ObjC optional).

I know there were discussions about marking members that should implement the protocol requirements with a keyword, but unfortunately, most members here were against such a proposal as it would introduce a lot of visual clutter.

I'm suggesting that implementing a same-named member from a protocol marked as "deprecated" that also has a default implementation would emit a warning.

Does anyone else view this as an issue in the language?


#2

I like this solution much better than the prior alternative.

When a protocol member is removed or renamed, marking it as deprecated is
the proper and natural thing to do. And when a conforming type implements a
deprecated requirement, there ought to be a warning.

This is vastly superior to the idea of mandating a keyword on every
conforming method and property.

Nevin

···

On Saturday, February 4, 2017, Charlie Monroe via swift-evolution < swift-evolution@swift.org> wrote:

I am currently working on updating some protocol APIs in a framework
that's shared among several of my projects. The issue here is that the
protocol has an extension with default implementation. For example:

protocol Foo {
    func doSomethingWithArray(_ arr: [String])
}

extension Foo {
    func doSomethingWithArray(_ arr: [String]) {
        print(arr)
    }
}

With this you can easily write

struct Bar: Foo { }

The issue comes when the struct actually implements the method and you
decide to rename it in the protocol:

struct Bar: Foo {
    func doSomethingWithArray(_ arr: [String]) {
        fatalError()
    }
}

protocol Foo {
    func doSomething(with arr: [String])
}

extension Foo {
    func doSomething(with arr: [String]) {
        print(arr)
    }
}

The code still compiles, yet the behavior of the app changes incredibly.
There is no way (to my knowledge) of marking some protocol members as
deprecated. I've tried the "obvious" solution:

extension Foo {
    @available(*, deprecated, renamed: "doSomething(with:)")
    func doSomethingWithArray(_ arr: [String]) {
        self.doSomething(with: arr)
    }
}

But unfortunately, this doesn't emit any warning on the Bar structure. I
personally believe that this is a major flaw, given that Swift is being
claimed as Protocol-Oriented language, there is no way to declare that a
protocol method is deprecated/renamed. Mainly with protocols with default
implementations (or in ObjC optional).

I know there were discussions about marking members that should implement
the protocol requirements with a keyword, but unfortunately, most members
here were against such a proposal as it would introduce a lot of visual
clutter.

I'm suggesting that implementing a same-named member from a protocol
marked as "deprecated" that also has a default implementation would emit a
warning.

Does anyone else view this as an issue in the language?