Weird function call behaviour


(David Hart) #1

In the following piece of code, can somebody explain the last result? Why the break in consistency? Is this a bug?

protocol P {
  func foo() -> String
}

extension P {
  func foo() -> String { return "P" }
}

class A : P {
  func foo() -> String { return "A" }
}

class B : P {}
class C : B {
  func foo() -> String { return "C" }
}

A().foo() // A
(A() as P).foo() // A
B().foo() // P
(B() as P).foo() // P
C().foo() // C
(C() as P).foo() // P


(Slava Pestov) #2

When a class conforms to a protocol and a requirement is fulfilled by a method in an extension, the class does not get a vtable entry for the extension method. So it cannot be overridden in a subclass — there’s nothing to dynamically dispatch here. We plan on addressing this as part of ABI stability.

Slava

···

On Feb 22, 2017, at 9:39 AM, David Hart via swift-users <swift-users@swift.org> wrote:

In the following piece of code, can somebody explain the last result? Why the break in consistency? Is this a bug?

protocol P {
  func foo() -> String
}

extension P {
  func foo() -> String { return "P" }
}

class A : P {
  func foo() -> String { return "A" }
}

class B : P {}
class C : B {
  func foo() -> String { return "C" }
}

A().foo() // A
(A() as P).foo() // A
B().foo() // P
(B() as P).foo() // P
C().foo() // C
(C() as P).foo() // P
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(David Hart) #3

When a class conforms to a protocol and a requirement is fulfilled by a method in an extension, the class does not get a vtable entry for the extension method. So it cannot be overridden in a subclass — there’s nothing to dynamically dispatch here. We plan on addressing this as part of ABI stability.

What do you mean by “address” this? Force the vtable entry?

···

On 22 Feb 2017, at 21:59, Slava Pestov via swift-users <swift-users@swift.org> wrote:

Slava

On Feb 22, 2017, at 9:39 AM, David Hart via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

In the following piece of code, can somebody explain the last result? Why the break in consistency? Is this a bug?

protocol P {
  func foo() -> String
}

extension P {
  func foo() -> String { return "P" }
}

class A : P {
  func foo() -> String { return "A" }
}

class B : P {}
class C : B {
  func foo() -> String { return "C" }
}

A().foo() // A
(A() as P).foo() // A
B().foo() // P
(B() as P).foo() // P
C().foo() // C
(C() as P).foo() // P
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto: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


(Slava Pestov) #4

When a class conforms to a protocol and a requirement is fulfilled by a method in an extension, the class does not get a vtable entry for the extension method. So it cannot be overridden in a subclass — there’s nothing to dynamically dispatch here. We plan on addressing this as part of ABI stability.

What do you mean by “address” this? Force the vtable entry?

Yeah. Instead of having the witness table for the conformance point directly to the extension method, if the conforming type is a class, we will generate a small thunk that calls a vtable entry, and store the extension method in that vtable entry.

Of course this will only work if the conformance is defined in the same translation unit as the class; if you define the extension in a different module, you’ll get the same behavior you observe below.

Slava

···

On Feb 22, 2017, at 1:01 PM, David Hart <david.w.hart@me.com> wrote:

On 22 Feb 2017, at 21:59, Slava Pestov via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Slava

On Feb 22, 2017, at 9:39 AM, David Hart via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

In the following piece of code, can somebody explain the last result? Why the break in consistency? Is this a bug?

protocol P {
  func foo() -> String
}

extension P {
  func foo() -> String { return "P" }
}

class A : P {
  func foo() -> String { return "A" }
}

class B : P {}
class C : B {
  func foo() -> String { return "C" }
}

A().foo() // A
(A() as P).foo() // A
B().foo() // P
(B() as P).foo() // P
C().foo() // C
(C() as P).foo() // P
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

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


(David Hart) #5

When a class conforms to a protocol and a requirement is fulfilled by a method in an extension, the class does not get a vtable entry for the extension method. So it cannot be overridden in a subclass — there’s nothing to dynamically dispatch here. We plan on addressing this as part of ABI stability.

What do you mean by “address” this? Force the vtable entry?

Yeah. Instead of having the witness table for the conformance point directly to the extension method, if the conforming type is a class, we will generate a small thunk that calls a vtable entry, and store the extension method in that vtable entry.

Of course this will only work if the conformance is defined in the same translation unit as the class; if you define the extension in a different module, you’ll get the same behavior you observe below.

Sound great :slight_smile:

···

On 22 Feb 2017, at 22:02, Slava Pestov via swift-users <swift-users@swift.org> wrote:

On Feb 22, 2017, at 1:01 PM, David Hart <david.w.hart@me.com <mailto:david.w.hart@me.com>> wrote:

On 22 Feb 2017, at 21:59, Slava Pestov via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Slava

Slava

On Feb 22, 2017, at 9:39 AM, David Hart via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

In the following piece of code, can somebody explain the last result? Why the break in consistency? Is this a bug?

protocol P {
  func foo() -> String
}

extension P {
  func foo() -> String { return "P" }
}

class A : P {
  func foo() -> String { return "A" }
}

class B : P {}
class C : B {
  func foo() -> String { return "C" }
}

A().foo() // A
(A() as P).foo() // A
B().foo() // P
(B() as P).foo() // P
C().foo() // C
(C() as P).foo() // P
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto: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