Compiler should issue a warning when a subclass implementation with default values matches a parent implementation without them


(Wagner Truppel) #1

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
    func foo() {
        print("Parent foo() called")
    }
}

class Child: Parent {
    func foo(x: Int = 0) {
        print("Child foo() called")
    }
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

Wagner


(Saagar Jha) #2

I’m not quite sure what you mean by "restrictions of parent implementations”, however, the “default value” you’re mentioning is a fundamental part of OOP–when a subclass overrides a superclass, it gets the parent class’s methods for free. There’s no need to issue a warning for this, since it’s expected behavior from other Object-Oriented languages.

Saagar Jha

···

On Jan 4, 2017, at 6:29 PM, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
   func foo() {
       print("Parent foo() called")
   }
}

class Child: Parent {
   func foo(x: Int = 0) {
       print("Child foo() called")
   }
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

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


(Wagner Truppel) #3

I’m afraid I wasn’t clear enough on my post. The default value I referred to is the “= 0”. Had it been absent, the call c.foo() would undeniably be fulfilled by the parent class. However, with the default argument value, it’s not obvious whether c.foo() should be the parent’s implementation or the child’s implementation (with the argument set to the default value). That’s why I’m suggesting a compiler warning because it’s very easy to make the mistake of calling c.foo() expecting the child’s implementation and it may be a hard bug to track when it happens.

Wagner

···

On 5 Jan 2017, at 03:35, Saagar Jha <saagar@saagarjha.com> wrote:

I’m not quite sure what you mean by "restrictions of parent implementations”, however, the “default value” you’re mentioning is a fundamental part of OOP–when a subclass overrides a superclass, it gets the parent class’s methods for free. There’s no need to issue a warning for this, since it’s expected behavior from other Object-Oriented languages.

Saagar Jha

On Jan 4, 2017, at 6:29 PM, Wagner Truppel via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
   func foo() {
       print("Parent foo() called")
   }
}

class Child: Parent {
   func foo(x: Int = 0) {
       print("Child foo() called")
   }
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

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


(Rien) #4

As you know. there is no ambiguity, no warnings needed.
(The parameter is part of the identifier of the function)

Imo, this request falls into the category “do as I think, not as I say”.

That is a discussion without end. Personally I am against ANY warnings of this kind. The reason is that I want my code to compile warnings free (default compiler behaviour) and I do not want an extra pragma in the code to instruct the compiler that when I am calling “foo()” I do indeed want to call “foo()”.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl

···

On 05 Jan 2017, at 03:29, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
   func foo() {
       print("Parent foo() called")
   }
}

class Child: Parent {
   func foo(x: Int = 0) {
       print("Child foo() called")
   }
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

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


(Jacob Bandes-Storch) #5

The same ambiguity occurs even without inheritance:

class C {
    func foo() {}
    func foo(x: Int = 0) {}
}

Somewhat related: https://bugs.swift.org/browse/SR-1408

···

On Wed, Jan 4, 2017 at 7:42 PM, Wagner Truppel via swift-users < swift-users@swift.org> wrote:

I’m afraid I wasn’t clear enough on my post. The default value I referred
to is the “= 0”. Had it been absent, the call c.foo() would undeniably be
fulfilled by the parent class. However, with the default argument value,
it’s not obvious whether c.foo() should be the parent’s implementation or
the child’s implementation (with the argument set to the default value).
That’s why I’m suggesting a compiler warning because it’s very easy to make
the mistake of calling c.foo() expecting the child’s implementation and it
may be a hard bug to track when it happens.

Wagner

On 5 Jan 2017, at 03:35, Saagar Jha <saagar@saagarjha.com> wrote:

I’m not quite sure what you mean by "restrictions of parent
implementations”, however, the “default value” you’re mentioning is a
fundamental part of OOP–when a subclass overrides a superclass, it gets the
parent class’s methods for free. There’s no need to issue a warning for
this, since it’s expected behavior from other Object-Oriented languages.

Saagar Jha

On Jan 4, 2017, at 6:29 PM, Wagner Truppel via swift-users < > swift-users@swift.org> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at
swift-evolution. so I’ll try here first. Hopefully it will get to the right
group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
   func foo() {
       print("Parent foo() called")
   }
}

class Child: Parent {
   func foo(x: Int = 0) {
       print("Child foo() called")
   }
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method
foo(x:) but no direct implementation of foo() so the parent’s
implementation is invoked rather than the child's. That’s all fine except
that it is not very intuitive.

I would argue that the expectation is that the search for an
implementation should start with the subclass (which is does) but should
look at all possible restrictions of parent implementations, including the
restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly
even an error.

Thanks for reading.
Cheers,

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

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


(Wagner Truppel) #6

Indeed, and in this case as well the compiler issues no warning even though the ambiguity is evident. I had to try it on a playground to be sure that it’s the parameter-less foo() rather than the default-argumented foo(x:) that gets invoked when we call foo() on an instance.

Of course, both this ambiguity and the one I started with can be resolved by explicitly calling foo(x: 0) but, as that link points out, "What is the point of having an optional parameter (a parameter with a default value) if you have to supply it anyway?”

More importantly, it’s an easy mistake to expect one implementation to be invoked rather than the other, with a potentially costly impact. The compiler has enough information to catch this and I think it should.

Wagner

···

On 5 Jan 2017, at 03:54, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

The same ambiguity occurs even without inheritance:

class C {
    func foo() {}
    func foo(x: Int = 0) {}
}

Somewhat related: https://bugs.swift.org/browse/SR-1408

On Wed, Jan 4, 2017 at 7:42 PM, Wagner Truppel via swift-users <swift-users@swift.org> wrote:
I’m afraid I wasn’t clear enough on my post. The default value I referred to is the “= 0”. Had it been absent, the call c.foo() would undeniably be fulfilled by the parent class. However, with the default argument value, it’s not obvious whether c.foo() should be the parent’s implementation or the child’s implementation (with the argument set to the default value). That’s why I’m suggesting a compiler warning because it’s very easy to make the mistake of calling c.foo() expecting the child’s implementation and it may be a hard bug to track when it happens.

Wagner

On 5 Jan 2017, at 03:35, Saagar Jha <saagar@saagarjha.com> wrote:

I’m not quite sure what you mean by "restrictions of parent implementations”, however, the “default value” you’re mentioning is a fundamental part of OOP–when a subclass overrides a superclass, it gets the parent class’s methods for free. There’s no need to issue a warning for this, since it’s expected behavior from other Object-Oriented languages.

Saagar Jha

On Jan 4, 2017, at 6:29 PM, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
   func foo() {
       print("Parent foo() called")
   }
}

class Child: Parent {
   func foo(x: Int = 0) {
       print("Child foo() called")
   }
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

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

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


(David Hart) #7

I think we need a warning because it is definitely ambiguous and a common pitfall for users of an API. The only solution would be for the APIs be written so to avoid those ambiguities I think.

···

On 5 Jan 2017, at 08:58, Rien via swift-users <swift-users@swift.org> wrote:

As you know. there is no ambiguity, no warnings needed.
(The parameter is part of the identifier of the function)

Imo, this request falls into the category “do as I think, not as I say”.

That is a discussion without end. Personally I am against ANY warnings of this kind. The reason is that I want my code to compile warnings free (default compiler behaviour) and I do not want an extra pragma in the code to instruct the compiler that when I am calling “foo()” I do indeed want to call “foo()”.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl

On 05 Jan 2017, at 03:29, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
  func foo() {
      print("Parent foo() called")
  }
}

class Child: Parent {
  func foo(x: Int = 0) {
      print("Child foo() called")
  }
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

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

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


(Saagar Jha) #8

Ahh, I get what you’re saying now. In this case I’d like to see a warning when a “conflicting” function is defined that there may be potential ambiguity.

Saagar Jha

···

On Jan 4, 2017, at 8:19 PM, Wagner Truppel <trupwl@gmail.com> wrote:

Indeed, and in this case as well the compiler issues no warning even though the ambiguity is evident. I had to try it on a playground to be sure that it’s the parameter-less foo() rather than the default-argumented foo(x:) that gets invoked when we call foo() on an instance.

Of course, both this ambiguity and the one I started with can be resolved by explicitly calling foo(x: 0) but, as that link points out, "What is the point of having an optional parameter (a parameter with a default value) if you have to supply it anyway?”

More importantly, it’s an easy mistake to expect one implementation to be invoked rather than the other, with a potentially costly impact. The compiler has enough information to catch this and I think it should.

Wagner

On 5 Jan 2017, at 03:54, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

The same ambiguity occurs even without inheritance:

class C {
   func foo() {}
   func foo(x: Int = 0) {}
}

Somewhat related: https://bugs.swift.org/browse/SR-1408

On Wed, Jan 4, 2017 at 7:42 PM, Wagner Truppel via swift-users <swift-users@swift.org> wrote:
I’m afraid I wasn’t clear enough on my post. The default value I referred to is the “= 0”. Had it been absent, the call c.foo() would undeniably be fulfilled by the parent class. However, with the default argument value, it’s not obvious whether c.foo() should be the parent’s implementation or the child’s implementation (with the argument set to the default value). That’s why I’m suggesting a compiler warning because it’s very easy to make the mistake of calling c.foo() expecting the child’s implementation and it may be a hard bug to track when it happens.

Wagner

On 5 Jan 2017, at 03:35, Saagar Jha <saagar@saagarjha.com> wrote:

I’m not quite sure what you mean by "restrictions of parent implementations”, however, the “default value” you’re mentioning is a fundamental part of OOP–when a subclass overrides a superclass, it gets the parent class’s methods for free. There’s no need to issue a warning for this, since it’s expected behavior from other Object-Oriented languages.

Saagar Jha

On Jan 4, 2017, at 6:29 PM, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
  func foo() {
      print("Parent foo() called")
  }
}

class Child: Parent {
  func foo(x: Int = 0) {
      print("Child foo() called")
  }
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

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

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


(Wagner Truppel) #9

Right, so several people have agreed with me that a compiler warning is in order. My question now is: what’s the best way to get this request to the people who can make it happen? swift-dev list? swift-evolution list? Apple radar? Suggestions are welcome.

Thanks.
Wagner

···

On 9 Jan 2017, at 09:49, David Hart <david@hartbit.com> wrote:

I think we need a warning because it is definitely ambiguous and a common pitfall for users of an API. The only solution would be for the APIs be written so to avoid those ambiguities I think.

On 5 Jan 2017, at 08:58, Rien via swift-users <swift-users@swift.org> wrote:

As you know. there is no ambiguity, no warnings needed.
(The parameter is part of the identifier of the function)

Imo, this request falls into the category “do as I think, not as I say”.

That is a discussion without end. Personally I am against ANY warnings of this kind. The reason is that I want my code to compile warnings free (default compiler behaviour) and I do not want an extra pragma in the code to instruct the compiler that when I am calling “foo()” I do indeed want to call “foo()”.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl

On 05 Jan 2017, at 03:29, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
func foo() {
     print("Parent foo() called")
}
}

class Child: Parent {
func foo(x: Int = 0) {
     print("Child foo() called")
}
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

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

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


(Quinn “The Eskimo!”) #10

File a Swift bug report.

<https://bugs.swift.org/>

Please post your bug number, just for the record.

Share and Enjoy

···

On 23 Jan 2017, at 10:04, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

what’s the best way to get this request to the people who can make it happen

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(Alex Blewitt) #11

The right first step is to raise a bug on JIRA https://bugs.swift.org <https://bugs.swift.org/> with the example test case in the mail. It will then be assigned to the appropriate individuals and prioritised/fixed accordingly.

Alex

···

On 23 Jan 2017, at 10:04, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

Right, so several people have agreed with me that a compiler warning is in order. My question now is: what’s the best way to get this request to the people who can make it happen? swift-dev list? swift-evolution list? Apple radar? Suggestions are welcome.

Thanks.
Wagner

On 9 Jan 2017, at 09:49, David Hart <david@hartbit.com> wrote:

I think we need a warning because it is definitely ambiguous and a common pitfall for users of an API. The only solution would be for the APIs be written so to avoid those ambiguities I think.

On 5 Jan 2017, at 08:58, Rien via swift-users <swift-users@swift.org> wrote:

As you know. there is no ambiguity, no warnings needed.
(The parameter is part of the identifier of the function)

Imo, this request falls into the category “do as I think, not as I say”.

That is a discussion without end. Personally I am against ANY warnings of this kind. The reason is that I want my code to compile warnings free (default compiler behaviour) and I do not want an extra pragma in the code to instruct the compiler that when I am calling “foo()” I do indeed want to call “foo()”.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl

On 05 Jan 2017, at 03:29, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

Hello,

I wasn’t sure whether to post this message here, at swift-dev, or at swift-evolution. so I’ll try here first. Hopefully it will get to the right group of people or, if not, someone will point me to the right mailing list.

I came across a situation that boils down to this example:

class Parent {
func foo() {
    print("Parent foo() called")
}
}

class Child: Parent {
func foo(x: Int = 0) {
    print("Child foo() called")
}
}

let c = Child()
c.foo() // prints "Parent foo() called"

I understand why this behaves like so, namely, the subclass has a method foo(x:) but no direct implementation of foo() so the parent’s implementation is invoked rather than the child's. That’s all fine except that it is not very intuitive.

I would argue that the expectation is that the search for an implementation should start with the subclass (which is does) but should look at all possible restrictions of parent implementations, including the restriction due to default values.

At the very least, I think the compiler should emit a warning or possibly even an error.

Thanks for reading.
Cheers,

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

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

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


(Zhao Xin) #12

I doubt if you could have done that in swift-evolution list. As for an
evolution, it requests that you not only provides the question, but also
must provide the answer and how to implementing in code together.

Zhaoxin

···

On Mon, Jan 23, 2017 at 6:04 PM, Wagner Truppel via swift-users < swift-users@swift.org> wrote:

Right, so several people have agreed with me that a compiler warning is in
order. My question now is: what’s the best way to get this request to the
people who can make it happen? swift-dev list? swift-evolution list? Apple
radar? Suggestions are welcome.

Thanks.
Wagner

> On 9 Jan 2017, at 09:49, David Hart <david@hartbit.com> wrote:
>
> I think we need a warning because it is definitely ambiguous and a
common pitfall for users of an API. The only solution would be for the APIs
be written so to avoid those ambiguities I think.
>
>> On 5 Jan 2017, at 08:58, Rien via swift-users <swift-users@swift.org> > wrote:
>>
>> As you know. there is no ambiguity, no warnings needed.
>> (The parameter is part of the identifier of the function)
>>
>> Imo, this request falls into the category “do as I think, not as I say”.
>>
>> That is a discussion without end. Personally I am against ANY warnings
of this kind. The reason is that I want my code to compile warnings free
(default compiler behaviour) and I do not want an extra pragma in the code
to instruct the compiler that when I am calling “foo()” I do indeed want to
call “foo()”.
>>
>> Regards,
>> Rien
>>
>> Site: http://balancingrock.nl
>> Blog: http://swiftrien.blogspot.com
>> Github: http://github.com/Swiftrien
>> Project: http://swiftfire.nl
>>
>>
>>
>>
>>> On 05 Jan 2017, at 03:29, Wagner Truppel via swift-users < > swift-users@swift.org> wrote:
>>>
>>> Hello,
>>>
>>> I wasn’t sure whether to post this message here, at swift-dev, or at
swift-evolution. so I’ll try here first. Hopefully it will get to the right
group of people or, if not, someone will point me to the right mailing list.
>>>
>>> I came across a situation that boils down to this example:
>>>
>>> class Parent {
>>> func foo() {
>>> print("Parent foo() called")
>>> }
>>> }
>>>
>>> class Child: Parent {
>>> func foo(x: Int = 0) {
>>> print("Child foo() called")
>>> }
>>> }
>>>
>>> let c = Child()
>>> c.foo() // prints "Parent foo() called"
>>>
>>> I understand why this behaves like so, namely, the subclass has a
method foo(x:) but no direct implementation of foo() so the parent’s
implementation is invoked rather than the child's. That’s all fine except
that it is not very intuitive.
>>>
>>> I would argue that the expectation is that the search for an
implementation should start with the subclass (which is does) but should
look at all possible restrictions of parent implementations, including the
restriction due to default values.
>>>
>>> At the very least, I think the compiler should emit a warning or
possibly even an error.
>>>
>>> Thanks for reading.
>>> Cheers,
>>>
>>> Wagner
>>> _______________________________________________
>>> swift-users mailing list
>>> swift-users@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>> _______________________________________________
>> swift-users mailing list
>> swift-users@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
>

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


(Wagner Truppel) #13

Ah, excellent! Thanks! Will do shortly.

···

On 23 Jan 2017, at 10:24, Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:

what’s the best way to get this request to the people who can make it happen

File a Swift bug report.

<https://bugs.swift.org/>

Please post your bug number, just for the record.

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

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


(Wagner Truppel) #14

Issued created: https://bugs.swift.org/browse/SR-3700

···

On 23 Jan 2017, at 10:24, Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:

what’s the best way to get this request to the people who can make it happen

File a Swift bug report.

<https://bugs.swift.org/>

Please post your bug number, just for the record.

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

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


(Wagner Truppel) #15

Say you have a protocol and an extension of it, like so:

protocol P {
   var item: String { get }
}

extension P {
   var item: String {
       return "P"
   }
}

Now imagine a class that conforms to that protocol and uses the property declared there but doesn’t specialise it in any way:

class A: P {
   var usedItem: String {
       return item // A uses 'item' but doesn't override or specialise it in any way
   }
}

let a = A()
a.item // returns “P"
a.usedItem // returns “P"

Not surprisingly, both results equal “P” since A doesn’t specialise 'item'. Now imagine a class B that subclasses A and *does* specialise 'item':

class B: A {
   var item: String { // subclass specialises 'item' by "overriding" the protocol extension implementation
       return "B"
   }
}

let b = B()
b.item // returns “B”

No surprise there either. B specialises 'item' so that’s what gets used. But...

b.usedItem // returns “P” !!?

I can hear you thinking "That's because 'usedItem' is being statically dispatched, since it's not declared in the protocol" but adding a declaration for 'usedItem' to the protocol doesn't help! I'll get to that in a moment.

Now consider class C, which is similar to B but also overrides A’s implementation of 'usedItem' to do, well, exactly what A does (at least syntactically):

class C: A {
   var item: String {
       return "C"
   }
   override var usedItem: String {
       return item
   }
}

let c = C()
c.item
c.usedItem

Now we get “C” for both calls, as desired, but having to add the override keyword just for this is ugly at best. What, then, if we did add a declaration for 'usedItem' to the protocol?

protocol P {
   var item: String { get }
   var usedItem: String { get }
}

extension P {
   var item: String {
       return "P"
   }
   var usedItem: String {
       return item
   }
}

class A: P {
}

let a = A()
a.item // returns “P"
a.usedItem // returns “P"

No surprises here.

class B: A {
   var item: String {
       return "B"
   }
}

let b = B()
b.item // returns “B”
b.usedItem // still returns “P” !!

The result is still "P", even though 'usedItem' is now being dynamically dispatched. Yes, B doesn't specialise the protocol extension's implementation of 'usedItem' so there really isn't an implementation of that to dynamically dispatch but =that shouldn't matter= (yet it does). B does specialise 'item', though, so *that* should be dynamically dispatched (since it is declared in the protocol). And it is, if called directly, but if it's called from within the protocol extension's default implementation of another dynamically dispatched invocation that isn't itself specialised, then it's not.

Of course, there's a solution similar to that of class C but, like that solution, this one also involves the presence of extra code that is syntactially identical to the default implementation.

class C: A {
   var item: String {
       return "C"
   }
   var usedItem: String {
       return item
   }
}

let c = C()
c.item // returns “C”
c.usedItem // now returns “C”, as desired.

What I find most surprising is that the static or dynamic dispatch behaviour of a method in the protocol extension is not determined solely by the absence or presence of its declaration in the protocol but also by whether or not conforming types actually have a specialised implementation. As I pointed out above, that second bit should not matter, yet it does. It seems to me that this is a bug in how protocol extensions work but I might be wrong about that.

Any thoughts?

Thanks.
Wagner


(Slava Pestov) #16

Say you have a protocol and an extension of it, like so:

protocol P {
  var item: String { get }
}

extension P {
  var item: String {
      return "P"
  }
}

Now imagine a class that conforms to that protocol and uses the property declared there but doesn’t specialise it in any way:

class A: P {
  var usedItem: String {
      return item // A uses 'item' but doesn't override or specialise it in any way
  }
}

let a = A()
a.item // returns “P"
a.usedItem // returns “P"

Not surprisingly, both results equal “P” since A doesn’t specialise 'item'. Now imagine a class B that subclasses A and *does* specialise 'item':

class B: A {
  var item: String { // subclass specialises 'item' by "overriding" the protocol extension implementation

This is the problem. You’re not overriding the protocol extension version, you’re just shadowing it for the purposes of compile-time name lookup. Note that if you add the ‘override’ keyword here, the compiler complains because there’s nothing in the base class to override.

At least in the case where the conformance is defined in the same module as the type, we could add new vtable entries to the class to allow the protocol extension method to be overridden in subclasses. But that’s not implemented yet.

Slava

···

On Jan 23, 2017, at 7:31 AM, Wagner Truppel via swift-users <swift-users@swift.org> wrote:

      return "B"
  }
}

let b = B()
b.item // returns “B”

No surprise there either. B specialises 'item' so that’s what gets used. But...

b.usedItem // returns “P” !!?

I can hear you thinking "That's because 'usedItem' is being statically dispatched, since it's not declared in the protocol" but adding a declaration for 'usedItem' to the protocol doesn't help! I'll get to that in a moment.

Now consider class C, which is similar to B but also overrides A’s implementation of 'usedItem' to do, well, exactly what A does (at least syntactically):

class C: A {
  var item: String {
      return "C"
  }
  override var usedItem: String {
      return item
  }
}

let c = C()
c.item
c.usedItem

Now we get “C” for both calls, as desired, but having to add the override keyword just for this is ugly at best. What, then, if we did add a declaration for 'usedItem' to the protocol?

protocol P {
  var item: String { get }
  var usedItem: String { get }
}

extension P {
  var item: String {
      return "P"
  }
  var usedItem: String {
      return item
  }
}

class A: P {
}

let a = A()
a.item // returns “P"
a.usedItem // returns “P"

No surprises here.

class B: A {
  var item: String {
      return "B"
  }
}

let b = B()
b.item // returns “B”
b.usedItem // still returns “P” !!

The result is still "P", even though 'usedItem' is now being dynamically dispatched. Yes, B doesn't specialise the protocol extension's implementation of 'usedItem' so there really isn't an implementation of that to dynamically dispatch but =that shouldn't matter= (yet it does). B does specialise 'item', though, so *that* should be dynamically dispatched (since it is declared in the protocol). And it is, if called directly, but if it's called from within the protocol extension's default implementation of another dynamically dispatched invocation that isn't itself specialised, then it's not.

Of course, there's a solution similar to that of class C but, like that solution, this one also involves the presence of extra code that is syntactially identical to the default implementation.

class C: A {
  var item: String {
      return "C"
  }
  var usedItem: String {
      return item
  }
}

let c = C()
c.item // returns “C”
c.usedItem // now returns “C”, as desired.

What I find most surprising is that the static or dynamic dispatch behaviour of a method in the protocol extension is not determined solely by the absence or presence of its declaration in the protocol but also by whether or not conforming types actually have a specialised implementation. As I pointed out above, that second bit should not matter, yet it does. It seems to me that this is a bug in how protocol extensions work but I might be wrong about that.

Any thoughts?

Thanks.
Wagner
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Wagner Truppel) #17

Yes, that's why I wrote overriding in quotes and also why I tried to use the word specialise in place of override. My beef is not really here; this really was just a preamble. My issue is with the fact that adding the declaration to the protocol doesn't solve the problem despite the fact that the property is then supposed to be dynamically dispatched but isn't.

···

On 23 Jan 2017, at 19:56, Slava Pestov <spestov@apple.com> wrote:

class B: A {
var item: String { // subclass specialises 'item' by "overriding" the protocol extension implementation

This is the problem. You’re not overriding the protocol extension version, you’re just shadowing it for the purposes of compile-time name lookup. Note that if you add the ‘override’ keyword here, the compiler complains because there’s nothing in the base class to override.


(Zhao Xin) #18

Wagner, the `extension` of `protocol` is never dynamic. It is `fail safe`.
It means if you don't implement something, the compiler will use the
implementation in the `protocol extension`. As in swift, struct and enum
can also conform protocols.

If you want the other way, you should do it in a base class, not in a
protocol extension.

Zhaoxin

···

On Tue, Jan 24, 2017 at 4:32 AM, Wagner Truppel via swift-users < swift-users@swift.org> wrote:

On 23 Jan 2017, at 19:56, Slava Pestov <spestov@apple.com> wrote:

class B: A {

var item: String { // subclass specialises 'item' by "overriding" the
protocol extension implementation

This is the problem. You’re not overriding the protocol extension version,
you’re just shadowing it for the purposes of compile-time name lookup. Note
that if you add the ‘override’ keyword here, the compiler complains because
there’s nothing in the base class to override.

Yes, that's why I wrote overriding in quotes and also why I tried to use
the word specialise in place of override. My beef is not really here; this
really was just a preamble. My issue is with the fact that adding the
declaration to the protocol doesn't solve the problem despite the fact that
the property is then supposed to be dynamically dispatched but isn't.

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