Keyword for protocol conformance


(David Cordero) #1

*The problem:*
At the moment, looking at the code of a class or a struct implementing a
protocol, it is hard to know what methods are actually implementing the
protocol and what other methods are just part of the code of the class or
struct.

People are trying to fix this problem with pragma marks or moving the code
conforming the protocol to a separate extension, but they are just specific
good practices or code styles.

*Proposal:*
Adding a keyword to the methods conforming protocols. As an example please
check the following piece of code which uses the keyword `conform` to
explicitly indicate that `myMethod` is a method conforming a protocol.

protocol MyProtocol {
    func myMethod() -> String
}

class MyClass: MyProtocol {

    *conform* func myMethod() -> String {
        return "Yuhuuu,I am conforming \\o//"
    }

    func whatever() {
        print("I am a boring method and I don't conform anything")
    }
}

It would be something similar to the current keyword `override` but for
protocols.

Apart from improving code readability, It would allow the detection, in
compilation time, of errors due to code evolution. For example redundant
methods that no longer conform anything once the requirement is removed
from the protocol for whatever reason.

Looking forward your opinions and comments.

Kind Regards


(Charles Srstka) #2

Then how about making the keyword optional? A method or property with the keyword before it would throw an error if it didn’t exist in one of the protocols your type implements. This way, if you intended a method to satisfy a protocol but left a typo in it, or you changed the protocol’s signature in a refactoring or something, you’d get notified instead of not finding out about it until runtime.

Charles

···

On Aug 22, 2016, at 5:19 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

This has been proposed before in the past by several others (myself being one of them).

The key problem is that it cannot accommodate retroactive modeling. That is, you would not be able to conform existing types, the code for which you do not control, to a protocol of your own design. Retroactive modeling is an essential feature of Swift protocol-oriented programming.


(Charles Srstka) #3

There's been agreement even from the core team that the quality of diagnostics when conforming to a protocol is sub-par.

The modified rule you propose has also been suggested before. The reason it doesn't help is that (1) if a method signature is mismatched accidentally due to a typo, you get a compilation error already because your type doesn't conform to the protocol (it's the quality of the error message that needs improvement);

You don’t get any error at all if there’s a default value.

protocol P {
  func doSomething()
}

extension P {
  func doSomething() { print(“Do This Thing”) }
}

struct S: P {
  func doSomthing() { print(“Do This Instead”) } // Whoops, doesn’t get called. And we don’t find out until mysterious behavior occurs at runtime.
}

If there were a way to tell the compiler that the function was meant to satisfy a protocol, we could prevent the mistake above from occurring.

(2) otherwise, if your type fulfills all protocol requirements but also implements an additional method unnecessary for conformance, what is the harm that is being prevented by a compiler error?

The fact that implementing protocol requirements that have default values is, in effect, stringly typed.

Charles

···

On Aug 22, 2016, at 5:41 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:


(Xiaodi Wu) #4

This has been proposed before in the past by several others (myself being
one of them).

The key problem is that it cannot accommodate retroactive modeling. That
is, you would not be able to conform existing types, the code for which you
do not control, to a protocol of your own design. Retroactive modeling is
an essential feature of Swift protocol-oriented programming.

···

On Mon, Aug 22, 2016 at 4:30 PM David Cordero via swift-evolution < swift-evolution@swift.org> wrote:

*The problem:*
At the moment, looking at the code of a class or a struct implementing a
protocol, it is hard to know what methods are actually implementing the
protocol and what other methods are just part of the code of the class or
struct.

People are trying to fix this problem with pragma marks or moving the code
conforming the protocol to a separate extension, but they are just specific
good practices or code styles.

*Proposal:*
Adding a keyword to the methods conforming protocols. As an example please
check the following piece of code which uses the keyword `conform` to
explicitly indicate that `myMethod` is a method conforming a protocol.

protocol MyProtocol {
    func myMethod() -> String
}

class MyClass: MyProtocol {

    *conform* func myMethod() -> String {
        return "Yuhuuu,I am conforming \\o//"
    }

    func whatever() {
        print("I am a boring method and I don't conform anything")
    }
}

It would be something similar to the current keyword `override` but for
protocols.

Apart from improving code readability, It would allow the detection, in
compilation time, of errors due to code evolution. For example redundant
methods that no longer conform anything once the requirement is removed
from the protocol for whatever reason.

Looking forward your opinions and comments.

Kind Regards

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


(Xiaodi Wu) #5

There's been agreement even from the core team that the quality of
diagnostics when conforming to a protocol is sub-par.

The modified rule you propose has also been suggested before. The reason it
doesn't help is that (1) if a method signature is mismatched accidentally
due to a typo, you get a compilation error already because your type
doesn't conform to the protocol (it's the quality of the error message that
needs improvement); (2) otherwise, if your type fulfills all protocol
requirements but also implements an additional method unnecessary for
conformance, what is the harm that is being prevented by a compiler error?

···

On Mon, Aug 22, 2016 at 17:30 Charles Srstka <cocoadev@charlessoft.com> wrote:

On Aug 22, 2016, at 5:19 PM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

This has been proposed before in the past by several others (myself being
one of them).

The key problem is that it cannot accommodate retroactive modeling. That
is, you would not be able to conform existing types, the code for which you
do not control, to a protocol of your own design. Retroactive modeling is
an essential feature of Swift protocol-oriented programming.

Then how about making the keyword optional? A method or property with the
keyword before it would throw an error if it didn’t exist in one of the
protocols your type implements. This way, if you intended a method to
satisfy a protocol but left a typo in it, or you changed the protocol’s
signature in a refactoring or something, you’d get notified instead of not
finding out about it until runtime.

Charles


(Xiaodi Wu) #6

That's a good point. Since you're proposing an optional keyword, though,
aren't you describing a linter functionality?

···

On Mon, Aug 22, 2016 at 18:25 Charles Srstka <cocoadev@charlessoft.com> wrote:

On Aug 22, 2016, at 5:41 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

There's been agreement even from the core team that the quality of
diagnostics when conforming to a protocol is sub-par.

The modified rule you propose has also been suggested before. The reason
it doesn't help is that (1) if a method signature is mismatched
accidentally due to a typo, you get a compilation error already because
your type doesn't conform to the protocol (it's the quality of the error
message that needs improvement);

You don’t get any error at all if there’s a default value.

protocol P {
func doSomething()
}

extension P {
func doSomething() { print(“Do This Thing”) }
}

struct S: P {
func doSomthing() { print(“Do This Instead”) } // Whoops, doesn’t get
called. And we don’t find out until mysterious behavior occurs at runtime.
}

If there were a way to tell the compiler that the function was meant to
satisfy a protocol, we could prevent the mistake above from occurring.

(2) otherwise, if your type fulfills all protocol requirements but also
implements an additional method unnecessary for conformance, what is the
harm that is being prevented by a compiler error?

The fact that implementing protocol requirements that have default values
is, in effect, stringly typed.

Charles


(Charlie Monroe) #7

I don't see it as sub-par in this example (this actually happened to me):

@objc protocol Foo {
  optional func bar()
}

class FooImpl: Foo {
  func bar() { ... }
}

Now imagine that bar() gets renamed in the protocol to baz(). You get no warnings, nothing - since the bar() was optional (or can have default implementation as Chalers mentioned). FooImpl still conforms to Foo and bar() can live on there happily.

Yes, this could be solved by Xcode having a refactoring feature that works for Swift, or that you search & replace when renaming, but still doesn't solve when a 3rd party library does this and suddenly the behavior of your app changes completely. This goes against the compile-time safety Swift is about.

Currently, when you mark a method on a protocol as

@available(*, unavailable, renamed="baz")

you do not get any warnings either - perhaps that's the issue here. On the other hand, the naming may be completely coincidental and you can already have a method called bar() and it would then be impossible to conform to Foo unless you rename bar().

What I'd propose is not to make keyword optional. In case you implement the members declared by the protocol, mark it as @conforming (or conforming keyword?).

If it's retroactive modeling, redeclare the members. E.g.:

extension Bar: Foo {
  // The implementation will be taken from Bar's main implementation
  @conforming func bar()
}

But yeah, it's a bit of boilerplate...

···

On Aug 23, 2016, at 12:41 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

There's been agreement even from the core team that the quality of diagnostics when conforming to a protocol is sub-par.

The modified rule you propose has also been suggested before. The reason it doesn't help is that (1) if a method signature is mismatched accidentally due to a typo, you get a compilation error already because your type doesn't conform to the protocol (it's the quality of the error message that needs improvement); (2) otherwise, if your type fulfills all protocol requirements but also implements an additional method unnecessary for conformance, what is the harm that is being prevented by a compiler error?

On Mon, Aug 22, 2016 at 17:30 Charles Srstka <cocoadev@charlessoft.com <mailto:cocoadev@charlessoft.com>> wrote:

On Aug 22, 2016, at 5:19 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This has been proposed before in the past by several others (myself being one of them).

The key problem is that it cannot accommodate retroactive modeling. That is, you would not be able to conform existing types, the code for which you do not control, to a protocol of your own design. Retroactive modeling is an essential feature of Swift protocol-oriented programming.

Then how about making the keyword optional? A method or property with the keyword before it would throw an error if it didn’t exist in one of the protocols your type implements. This way, if you intended a method to satisfy a protocol but left a typo in it, or you changed the protocol’s signature in a refactoring or something, you’d get notified instead of not finding out about it until runtime.

Charles

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


(Robert Widmann) #8

~Robert Widmann

2016/08/22 14:30、David Cordero via swift-evolution <swift-evolution@swift.org> のメッセージ:

The problem:
At the moment, looking at the code of a class or a struct implementing a protocol, it is hard to know what methods are actually implementing the protocol and what other methods are just part of the code of the class or struct.

That seems like a feature, not a bug. Why should I as an author care whether a method contributes to a protocol conformance or not if the compiler can tell me that kind of information itself?

People are trying to fix this problem with pragma marks or moving the code conforming the protocol to a separate extension, but they are just specific good practices or code styles.

Hm? I haven't seen anything like this used. If you mean doc comments explaining which protocol things are tied to, then that just seems like a style choice.

Proposal:
Adding a keyword to the methods conforming protocols. As an example please check the following piece of code which uses the keyword `conform` to explicitly indicate that `myMethod` is a method conforming a protocol.

Please, no more keywords.

protocol MyProtocol {
    func myMethod() -> String
}

class MyClass: MyProtocol {

    conform func myMethod() -> String {
        return "Yuhuuu,I am conforming \\o//"
    }

    func whatever() {
        print("I am a boring method and I don't conform anything")
    }
}

It would be something similar to the current keyword `override` but for protocols.

Apart from improving code readability, It would allow the detection, in compilation time, of errors due to code evolution. For example redundant methods that no longer conform anything once the requirement is removed from the protocol for whatever reason.

If you make a breaking change to a protocol like this, you should have gone through a deprecation cycle to indicate to your clients the appropriate changes you're going to make to the protocol. This aspect of the change seems to if not encourage, highlight, bad behavior.

···

Looking forward your opinions and comments.

Kind Regards

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


(Charles Srstka) #9

If the optionality of the keyword bothers you, there are multiple ways to do it:

Solution #1: Optional keyword.

protocol P {
  func giveUpTheFunc()
}

struct S: P {
  implement func giveUpTheFunc()
}

Solution #2: Required keyword, but with a manual override for protocols that need to be retroactive.

protocol P {
  @retro func giveUpTheFunc()
}

struct S {
  func giveUpTheFunc()
}

extension S: P {}

Solution #3: No keyword, but extensions that conform to protocols can’t have anything other than protocol conformances unless they’re private.

protocol P {
  func giveUpTheFunc()
}

struct S {}

extension S: P {
  func giveUpTheFunc() {}
  func tearTheRoofOffTheSucker() {} // error!
}

but this is okay:

extension S: P {
  func giveUpTheFunc() {
    tearTheRoofOffTheSucker()
  }

  private func tearTheRoofOffTheSucker() {} // works :slight_smile:
}

There are definitely a range of ways to make protocol conformance more explicit. Which one is the best, I’m not sure, but we could probably flesh out the pros and cons of these, as well as any other options that I haven’t thought of, with some discussion.

Charles

···

On Aug 22, 2016, at 6:33 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

That's a good point. Since you're proposing an optional keyword, though, aren't you describing a linter functionality?


(Xiaodi Wu) #10

Sure, I too am not convinced we've exhausted all the design possibilities.
Here are some previous related threads (including one launched by a core
team member):

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005380.html

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160229/011792.html
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160425/015920.html

Somewhat related, but definitely a different topic:

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160516/018286.html

···

On Mon, Aug 22, 2016 at 7:02 PM, Charles Srstka <cocoadev@charlessoft.com> wrote:

On Aug 22, 2016, at 6:33 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
> That's a good point. Since you're proposing an optional keyword, though,
aren't you describing a linter functionality?

If the optionality of the keyword bothers you, there are multiple ways to
do it:

Solution #1: Optional keyword.

protocol P {
        func giveUpTheFunc()
}

struct S: P {
        implement func giveUpTheFunc()
}

Solution #2: Required keyword, but with a manual override for protocols
that need to be retroactive.

protocol P {
        @retro func giveUpTheFunc()
}

struct S {
        func giveUpTheFunc()
}

extension S: P {}

Solution #3: No keyword, but extensions that conform to protocols can’t
have anything other than protocol conformances unless they’re private.

protocol P {
        func giveUpTheFunc()
}

struct S {}

extension S: P {
        func giveUpTheFunc() {}
        func tearTheRoofOffTheSucker() {} // error!
}

but this is okay:

extension S: P {
        func giveUpTheFunc() {
                tearTheRoofOffTheSucker()
        }

        private func tearTheRoofOffTheSucker() {} // works :slight_smile:
}

There are definitely a range of ways to make protocol conformance more
explicit. Which one is the best, I’m not sure, but we could probably flesh
out the pros and cons of these, as well as any other options that I haven’t
thought of, with some discussion.

Charles


(Charles Srstka) #11

Had that happen to me a bunch of times, especially when I realize that the method needs to have one more argument and then forget to add it everywhere (which is harder to use search-and-replace for, as well).

Here’s another case where this can bite you:

In file P.swift:

protocol P {
  func foo()
}

extension P {
  func foo()
}

In another file, S.swift:

struct S: P {}

Imagine I rename foo in the protocol, but forget to rename it in the extension. The method no longer has a default implementation, and we do indeed get an error, but the error’s in S.swift, in the wrong place. S complains that it doesn’t conform to the protocol. If there were a keyword on foo() in the extension, the compiler warning would be right where the problem is as soon as I renamed the method in the protocol, and it’d be a 2-second fix.

Charles

···

On Aug 23, 2016, at 12:11 AM, Charlie Monroe <charlie@charliemonroe.net> wrote:

I don't see it as sub-par in this example (this actually happened to me):

@objc protocol Foo {
  optional func bar()
}

class FooImpl: Foo {
  func bar() { ... }
}

Now imagine that bar() gets renamed in the protocol to baz(). You get no warnings, nothing - since the bar() was optional (or can have default implementation as Chalers mentioned). FooImpl still conforms to Foo and bar() can live on there happily.


(David Cordero) #12

I agree with Charlie Monroe. I think it would improve the compile time
safety of Swift, making the keyword non optional.

The main issue with retroactive modelling is that it is applied to code to
which we might have no control at all. So this boilerplate definition would
allow the detection of changes on method signatures on this non controlled
code.

It might be easier to read having two different keywords for the 2
different cases. Something like the following code using `implement` when
implementing the protocol and `conform` when retroactive modeling

protocol MyProtocol {
    func method() -> String
}

class MyClass {

    implement func method() -> String {
        return "World"
    }
}

class MyNonControlledClass {

    func method() -> String {
        return "Hello"
    }
}

extension MyNonControlledClass: MyProtocol {
    conform method() -> String
}

Or even with a general way to declare a full conformance of a protocol:

extension MyNonControlledClass: conform(MyProtocol) {
}

···

On 23 August 2016 at 07:11, Charlie Monroe via swift-evolution < swift-evolution@swift.org> wrote:

I don't see it as sub-par in this example (this actually happened to me):

@objc protocol Foo {
optional func bar()
}

class FooImpl: Foo {
func bar() { ... }
}

Now imagine that bar() gets renamed in the protocol to baz(). You get no
warnings, nothing - since the bar() was optional (or can have default
implementation as Chalers mentioned). FooImpl still conforms to Foo and
bar() can live on there happily.

Yes, this could be solved by Xcode having a refactoring feature that works
for Swift, or that you search & replace when renaming, but still doesn't
solve when a 3rd party library does this and suddenly the behavior of your
app changes completely. This goes against the compile-time safety Swift is
about.

Currently, when you mark a method on a protocol as

@available(*, unavailable, renamed="baz")

you do not get any warnings either - perhaps that's the issue here. On the
other hand, the naming may be completely coincidental and you can already
have a method called bar() and it would then be impossible to conform to
Foo unless you rename bar().

What I'd propose is not to make keyword optional. In case you implement
the members declared by the protocol, mark it as @conforming (or conforming
keyword?).

If it's retroactive modeling, redeclare the members. E.g.:

extension Bar: Foo {
// The implementation will be taken from Bar's main implementation
@conforming func bar()
}

But yeah, it's a bit of boilerplate...

On Aug 23, 2016, at 12:41 AM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

There's been agreement even from the core team that the quality of
diagnostics when conforming to a protocol is sub-par.

The modified rule you propose has also been suggested before. The reason
it doesn't help is that (1) if a method signature is mismatched
accidentally due to a typo, you get a compilation error already because
your type doesn't conform to the protocol (it's the quality of the error
message that needs improvement); (2) otherwise, if your type fulfills all
protocol requirements but also implements an additional method unnecessary
for conformance, what is the harm that is being prevented by a compiler
error?

On Mon, Aug 22, 2016 at 17:30 Charles Srstka <cocoadev@charlessoft.com> > wrote:

On Aug 22, 2016, at 5:19 PM, Xiaodi Wu via swift-evolution < >> swift-evolution@swift.org> wrote:

This has been proposed before in the past by several others (myself being
one of them).

The key problem is that it cannot accommodate retroactive modeling. That
is, you would not be able to conform existing types, the code for which you
do not control, to a protocol of your own design. Retroactive modeling is
an essential feature of Swift protocol-oriented programming.

Then how about making the keyword optional? A method or property with the
keyword before it would throw an error if it didn’t exist in one of the
protocols your type implements. This way, if you intended a method to
satisfy a protocol but left a typo in it, or you changed the protocol’s
signature in a refactoring or something, you’d get notified instead of not
finding out about it until runtime.

Charles

_______________________________________________

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


(Sean Heber) #13

Just want to add my voice to the chorus of “this has happened to me too.”

l8r
Sean

···

On Aug 23, 2016, at 2:13 AM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

On Aug 23, 2016, at 12:11 AM, Charlie Monroe <charlie@charliemonroe.net> wrote:

I don't see it as sub-par in this example (this actually happened to me):

@objc protocol Foo {
  optional func bar()
}

class FooImpl: Foo {
  func bar() { ... }
}

Now imagine that bar() gets renamed in the protocol to baz(). You get no warnings, nothing - since the bar() was optional (or can have default implementation as Chalers mentioned). FooImpl still conforms to Foo and bar() can live on there happily.

Had that happen to me a bunch of times, especially when I realize that the method needs to have one more argument and then forget to add it everywhere (which is harder to use search-and-replace for, as well).

Here’s another case where this can bite you:

In file P.swift:

protocol P {
  func foo()
}

extension P {
  func foo()
}

In another file, S.swift:

struct S: P {}

Imagine I rename foo in the protocol, but forget to rename it in the extension. The method no longer has a default implementation, and we do indeed get an error, but the error’s in S.swift, in the wrong place. S complains that it doesn’t conform to the protocol. If there were a keyword on foo() in the extension, the compiler warning would be right where the problem is as soon as I renamed the method in the protocol, and it’d be a 2-second fix.

Charles

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


(Xiaodi Wu) #14

I don't see it as sub-par in this example (this actually happened to me):

@objc protocol Foo {
optional func bar()
}

class FooImpl: Foo {
func bar() { ... }
}

Now imagine that bar() gets renamed in the protocol to baz(). You get no
warnings, nothing - since the bar() was optional (or can have default
implementation as Chalers mentioned). FooImpl still conforms to Foo and
bar() can live on there happily.

I think we're having a language barrier here :slight_smile: Sub-par means inadequate,
and I think we're all in agreement that this behavior is inadequate.

Yes, this could be solved by Xcode having a refactoring feature that works
for Swift, or that you search & replace when renaming, but still doesn't
solve when a 3rd party library does this and suddenly the behavior of your
app changes completely. This goes against the compile-time safety Swift is
about.

Currently, when you mark a method on a protocol as

@available(*, unavailable, renamed="baz")

you do not get any warnings either - perhaps that's the issue here.

I think we should separate out the discussion about library evolution and
versioning. There's a huge amount of proposed and (I think) planned work
about that. Maybe the core team could chime in on how up-to-date this
document is:

https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst

If the true motivating problem here has to do with library evolution, then
we should probably study that document and wait to see how that planned
work turns out.

But if I understand it correctly, the true motivating problem here is the
poor experience of conforming to a protocol, the errors caused by typos
that effectively make protocol requirements stringily typed, and the
resultant unanticipated behaviors that arise, then we can have a useful
discussion about these issues without also trying to solve library
evolution with a single keyword.

···

On Tue, Aug 23, 2016 at 12:11 AM, Charlie Monroe <charlie@charliemonroe.net> wrote:

On the other hand, the naming may be completely coincidental and you can
already have a method called bar() and it would then be impossible to
conform to Foo unless you rename bar().

What I'd propose is not to make keyword optional. In case you implement
the members declared by the protocol, mark it as @conforming (or conforming
keyword?).

If it's retroactive modeling, redeclare the members. E.g.:

extension Bar: Foo {
// The implementation will be taken from Bar's main implementation
@conforming func bar()
}

But yeah, it's a bit of boilerplate...

On Aug 23, 2016, at 12:41 AM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

There's been agreement even from the core team that the quality of
diagnostics when conforming to a protocol is sub-par.

The modified rule you propose has also been suggested before. The reason
it doesn't help is that (1) if a method signature is mismatched
accidentally due to a typo, you get a compilation error already because
your type doesn't conform to the protocol (it's the quality of the error
message that needs improvement); (2) otherwise, if your type fulfills all
protocol requirements but also implements an additional method unnecessary
for conformance, what is the harm that is being prevented by a compiler
error?

On Mon, Aug 22, 2016 at 17:30 Charles Srstka <cocoadev@charlessoft.com> > wrote:

On Aug 22, 2016, at 5:19 PM, Xiaodi Wu via swift-evolution < >> swift-evolution@swift.org> wrote:

This has been proposed before in the past by several others (myself being
one of them).

The key problem is that it cannot accommodate retroactive modeling. That
is, you would not be able to conform existing types, the code for which you
do not control, to a protocol of your own design. Retroactive modeling is
an essential feature of Swift protocol-oriented programming.

Then how about making the keyword optional? A method or property with the
keyword before it would throw an error if it didn’t exist in one of the
protocols your type implements. This way, if you intended a method to
satisfy a protocol but left a typo in it, or you changed the protocol’s
signature in a refactoring or something, you’d get notified instead of not
finding out about it until runtime.

Charles

_______________________________________________

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


(Xiaodi Wu) #15

I don't see it as sub-par in this example (this actually happened to me):

@objc protocol Foo {
optional func bar()
}

class FooImpl: Foo {
func bar() { ... }
}

Now imagine that bar() gets renamed in the protocol to baz(). You get no
warnings, nothing - since the bar() was optional (or can have default
implementation as Chalers mentioned). FooImpl still conforms to Foo and
bar() can live on there happily.

Had that happen to me a bunch of times, especially when I realize that the
method needs to have one more argument and then forget to add it everywhere
(which is harder to use search-and-replace for, as well).

Here’s another case where this can bite you:

In file P.swift:

protocol P {
func foo()
}

extension P {
func foo()
}

In another file, S.swift:

struct S: P {}

Imagine I rename foo in the protocol, but forget to rename it in the
extension. The method no longer has a default implementation, and we do
indeed get an error, but the error’s in S.swift, in the wrong place. S
complains that it doesn’t conform to the protocol. If there were a keyword
on foo() in the extension, the compiler warning would be right where the
problem is as soon as I renamed the method in the protocol, and it’d be a
2-second fix.

This is a great motivating example, I think. I'm convinced that we need
some way to improve this scenario.

That said, it'd probably have to be opt-in because major source-breaking
changes are going to be frowned upon for Swift 4, and changing the syntax
for every single protocol conformance would be hugely source-breaking. That
said, I think an opt-in level of safety, where you mark particular
declarations or even entire extensions as `@conforming` (or some similar
syntax) would give the user most or all of these benefits while maintaining
source compatibility. I would be +1 on a proposal like that.

···

On Tue, Aug 23, 2016 at 2:13 AM, Charles Srstka <cocoadev@charlessoft.com> wrote:

On Aug 23, 2016, at 12:11 AM, Charlie Monroe <charlie@charliemonroe.net> > wrote:

Charles


(Charles Srstka) #16

2016/08/22 14:30、David Cordero via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> のメッセージ:

The problem:
At the moment, looking at the code of a class or a struct implementing a protocol, it is hard to know what methods are actually implementing the protocol and what other methods are just part of the code of the class or struct.

That seems like a feature, not a bug. Why should I as an author care whether a method contributes to a protocol conformance or not if the compiler can tell me that kind of information itself?

Being able to reason about your code, what it does, and what it’s for is undesirable?

protocol MyProtocol {
    func myMethod() -> String
}

class MyClass: MyProtocol {

    conform func myMethod() -> String {
        return "Yuhuuu,I am conforming \\o//"
    }

    func whatever() {
        print("I am a boring method and I don't conform anything")
    }
}

It would be something similar to the current keyword `override` but for protocols.

Apart from improving code readability, It would allow the detection, in compilation time, of errors due to code evolution. For example redundant methods that no longer conform anything once the requirement is removed from the protocol for whatever reason.

If you make a breaking change to a protocol like this, you should have gone through a deprecation cycle to indicate to your clients the appropriate changes you're going to make to the protocol. This aspect of the change seems to if not encourage, highlight, bad behavior.

What if it’s your own code and all the callers are internal? What if you’re still developing the protocol and haven’t released the API interface yet?

Charles

···

On Aug 23, 2016, at 2:33 PM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:


(Robert Widmann) #17

~Robert Widmann

2016/08/23 15:29、Charles Srstka <cocoadev@charlessoft.com> のメッセージ:

2016/08/22 14:30、David Cordero via swift-evolution <swift-evolution@swift.org> のメッセージ:

The problem:
At the moment, looking at the code of a class or a struct implementing a protocol, it is hard to know what methods are actually implementing the protocol and what other methods are just part of the code of the class or struct.

That seems like a feature, not a bug. Why should I as an author care whether a method contributes to a protocol conformance or not if the compiler can tell me that kind of information itself?

Being able to reason about your code, what it does, and what it’s for is undesirable?

That's not an answer to the question I asked. Why is this significant enough to warrant an entire keyword? The clutter of a whole keyword that does nothing but wait for a developer to make a source-compatible binary-breaking change to an interface does not seem worth it. Maybe you can convince me otherwise.

protocol MyProtocol {
    func myMethod() -> String
}

class MyClass: MyProtocol {

    conform func myMethod() -> String {
        return "Yuhuuu,I am conforming \\o//"
    }

    func whatever() {
        print("I am a boring method and I don't conform anything")
    }
}

It would be something similar to the current keyword `override` but for protocols.

Apart from improving code readability, It would allow the detection, in compilation time, of errors due to code evolution. For example redundant methods that no longer conform anything once the requirement is removed from the protocol for whatever reason.

If you make a breaking change to a protocol like this, you should have gone through a deprecation cycle to indicate to your clients the appropriate changes you're going to make to the protocol. This aspect of the change seems to if not encourage, highlight, bad behavior.

What if it’s your own code and all the callers are internal? What if you’re still developing the protocol and haven’t released the API interface yet?

Then your concerns are local enough that you know where all implementations of the protocol lie and whether they require deletion or not. The point about deprecation cycles still stands in all the cases you mention. Just because the interface is private doesn't mean you can't take responsibility for keeping it as clean as you can.

Charles

tl;dr It seems like all of this can be subsumed by us warning about dead code.

···

On Aug 23, 2016, at 2:33 PM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:


(David Cordero) #18

It sounds to me.

In fact it looks like we already have quite interesting information to
prepare a rough Draft to summarise all these scenarios in a real proposal.

···

On 23 August 2016 at 17:50, Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote:

On Tue, Aug 23, 2016 at 2:13 AM, Charles Srstka <cocoadev@charlessoft.com> > wrote:

On Aug 23, 2016, at 12:11 AM, Charlie Monroe <charlie@charliemonroe.net> >> wrote:

I don't see it as sub-par in this example (this actually happened to me):

@objc protocol Foo {
optional func bar()
}

class FooImpl: Foo {
func bar() { ... }
}

Now imagine that bar() gets renamed in the protocol to baz(). You get no
warnings, nothing - since the bar() was optional (or can have default
implementation as Chalers mentioned). FooImpl still conforms to Foo and
bar() can live on there happily.

Had that happen to me a bunch of times, especially when I realize that
the method needs to have one more argument and then forget to add it
everywhere (which is harder to use search-and-replace for, as well).

Here’s another case where this can bite you:

In file P.swift:

protocol P {
func foo()
}

extension P {
func foo()
}

In another file, S.swift:

struct S: P {}

Imagine I rename foo in the protocol, but forget to rename it in the
extension. The method no longer has a default implementation, and we do
indeed get an error, but the error’s in S.swift, in the wrong place. S
complains that it doesn’t conform to the protocol. If there were a keyword
on foo() in the extension, the compiler warning would be right where the
problem is as soon as I renamed the method in the protocol, and it’d be a
2-second fix.

This is a great motivating example, I think. I'm convinced that we need
some way to improve this scenario.

That said, it'd probably have to be opt-in because major source-breaking
changes are going to be frowned upon for Swift 4, and changing the syntax
for every single protocol conformance would be hugely source-breaking. That
said, I think an opt-in level of safety, where you mark particular
declarations or even entire extensions as `@conforming` (or some similar
syntax) would give the user most or all of these benefits while maintaining
source compatibility. I would be +1 on a proposal like that.

Charles

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


(Charles Srstka) #19

2016/08/23 15:29、Charles Srstka <cocoadev@charlessoft.com <mailto:cocoadev@charlessoft.com>> のメッセージ:

2016/08/22 14:30、David Cordero via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> のメッセージ:

The problem:
At the moment, looking at the code of a class or a struct implementing a protocol, it is hard to know what methods are actually implementing the protocol and what other methods are just part of the code of the class or struct.

That seems like a feature, not a bug. Why should I as an author care whether a method contributes to a protocol conformance or not if the compiler can tell me that kind of information itself?

Being able to reason about your code, what it does, and what it’s for is undesirable?

That's not an answer to the question I asked. Why is this significant enough to warrant an entire keyword? The clutter of a whole keyword that does nothing but wait for a developer to make a source-compatible binary-breaking change to an interface does not seem worth it. Maybe you can convince me otherwise.

Same reason overriding a class method warrants a keyword. It expresses the purpose more clearly, and allows the compiler to catch mistakes for us.

protocol MyProtocol {
    func myMethod() -> String
}

class MyClass: MyProtocol {

    conform func myMethod() -> String {
        return "Yuhuuu,I am conforming \\o// <smb://o//>"
    }

    func whatever() {
        print("I am a boring method and I don't conform anything")
    }
}

It would be something similar to the current keyword `override` but for protocols.

Apart from improving code readability, It would allow the detection, in compilation time, of errors due to code evolution. For example redundant methods that no longer conform anything once the requirement is removed from the protocol for whatever reason.

If you make a breaking change to a protocol like this, you should have gone through a deprecation cycle to indicate to your clients the appropriate changes you're going to make to the protocol. This aspect of the change seems to if not encourage, highlight, bad behavior.

What if it’s your own code and all the callers are internal? What if you’re still developing the protocol and haven’t released the API interface yet?

Then your concerns are local enough that you know where all implementations of the protocol lie and whether they require deletion or not. The point about deprecation cycles still stands in all the cases you mention. Just because the interface is private doesn't mean you can't take responsibility for keeping it as clean as you can.

Charles

tl;dr It seems like all of this can be subsumed by us warning about dead code.

Did you look at my examples earlier in the thread? Neither of those would be caught by warning about dead code.

Charles

···

On Aug 23, 2016, at 10:34 PM, Robert Widmann <devteam.codafi@gmail.com> wrote:

On Aug 23, 2016, at 2:33 PM, Robert Widmann via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:


(Daniel Duan) #20

These are legitimate benefits of adding the keyword.

However, one of the earlier examples from the thread is solving a issue specific to Objective-C. The other seems to be an issue of convenience and can be solved by better compiler error reporting.

Do we really think these small gains justify the hefty price of a keyword added to the language?

···

On Aug 23, 2016, at 8:52 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

On Aug 23, 2016, at 10:34 PM, Robert Widmann <devteam.codafi@gmail.com <mailto:devteam.codafi@gmail.com>> wrote:

2016/08/23 15:29、Charles Srstka <cocoadev@charlessoft.com <mailto:cocoadev@charlessoft.com>> のメッセージ:

On Aug 23, 2016, at 2:33 PM, Robert Widmann via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

2016/08/22 14:30、David Cordero via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> のメッセージ:

The problem:
At the moment, looking at the code of a class or a struct implementing a protocol, it is hard to know what methods are actually implementing the protocol and what other methods are just part of the code of the class or struct.

That seems like a feature, not a bug. Why should I as an author care whether a method contributes to a protocol conformance or not if the compiler can tell me that kind of information itself?

Being able to reason about your code, what it does, and what it’s for is undesirable?

That's not an answer to the question I asked. Why is this significant enough to warrant an entire keyword? The clutter of a whole keyword that does nothing but wait for a developer to make a source-compatible binary-breaking change to an interface does not seem worth it. Maybe you can convince me otherwise.

Same reason overriding a class method warrants a keyword. It expresses the purpose more clearly, and allows the compiler to catch mistakes for us.

protocol MyProtocol {
    func myMethod() -> String
}

class MyClass: MyProtocol {

    conform func myMethod() -> String {
        return "Yuhuuu,I am conforming \\o// <smb://o//>"
    }

    func whatever() {
        print("I am a boring method and I don't conform anything")
    }
}

It would be something similar to the current keyword `override` but for protocols.

Apart from improving code readability, It would allow the detection, in compilation time, of errors due to code evolution. For example redundant methods that no longer conform anything once the requirement is removed from the protocol for whatever reason.

If you make a breaking change to a protocol like this, you should have gone through a deprecation cycle to indicate to your clients the appropriate changes you're going to make to the protocol. This aspect of the change seems to if not encourage, highlight, bad behavior.

What if it’s your own code and all the callers are internal? What if you’re still developing the protocol and haven’t released the API interface yet?

Then your concerns are local enough that you know where all implementations of the protocol lie and whether they require deletion or not. The point about deprecation cycles still stands in all the cases you mention. Just because the interface is private doesn't mean you can't take responsibility for keeping it as clean as you can.

Charles

tl;dr It seems like all of this can be subsumed by us warning about dead code.

Did you look at my examples earlier in the thread? Neither of those would be caught by warning about dead code.

Charles

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