Static Dispatch Pitfalls

Sorry, I understand and appreciate your pragmatism. Right now it feels
very much like a fight to the ideological death between POP and OOP
and it may get really bad results this way.

Being in the run-up to WWDC, I don't really have the time to participate
in this discussion right now, although I think it is important and
interesting. However, this last sentence caught my eye and I thought I
should clarify something: protocols unify static and dynamic dispatch,
and one is not inherently better than the other. They have different
strengths. Protocol-oriented programming is about leveraging those
strengths appropriately, not about a mandate to choose one or the other
form of dispatch.

Well said.
Maybe the issue is not about being unclear at the point of definition in the extension, but at the call site - similar to value vs. reference semantics.
Just as a thought experiment, putting aside that it would be ugly, would having a different syntax for invoking methods with static and dynamic dispatch help to understand the working of the code better?

Hello Chris,

I think that it would go along the line of thinking that sees static dispatching as an optimisation that should be either enforced by the developer's clear and explicit intent or performed automagically only if the compiler is sure of no side effects occurring.

···

Sent from my iPhone

On 20 May 2016, at 18:35, Chris Lattner <clattner@apple.com> wrote:

On May 20, 2016, at 9:17 AM, Austin Zheng <austinzheng@gmail.com> wrote:

I almost want to propose forbidding methods in protocol extensions unless they're also a requirement in the protocol itself, but I don't think that would fly.

I don’t think that would fly :-). That said, has anyone considered requiring a keyword on the method in the protocol extension that makes it explicit that the dispatch is non-dynamic?

-Chris

That said, has anyone considered requiring a keyword on the method in the protocol extension that makes it explicit that the dispatch is non-dynamic?

Many moons ago, I was pushing to require a `final` keyword on protocol extension methods, which would prevent conforming types from providing their own implementations. It was probably the first thing I worked on. There were long arguments about whether and how you could override the `final`-ness, people kept clamoring for dynamic dispatch, and I ultimately wasn't able to produce a consensus before I had to turn my attention back towards paying work.

···

--
Brent Royal-Gordon
Architechies

I almost want to propose forbidding methods in protocol extensions unless they're also a requirement in the protocol itself, but I don't think that would fly.

Austin

Thats one option.

Think two separate developers - only who implements the protocol Foo and has an independent bar() method on their type, and one who writes an extension to Foo to add a bar method on it.

bar() is not part of the protocol specification. the person implementing the type has no idea that others are expecting his bar() to meet particular requirements, just because it was declared in a protocol extension.

How is this the case? Don't you have to expect that others can use your protocol extension since it is visible to them?

If the conforming type is implemented in a separate module from the protocol extension that extension *is not* visible to them. They would have no expectation that their `bar` method had anything to do with the protocol which *is* visible to them in its originally declared form.

I think the static behavior should be an opt in feature so the common case is what everyone expects to happen.

A big part of the problem is that there are different perspectives on what is actually expected.

···

On May 20, 2016, at 12:12 PM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:
On May 20, 2016, at 12:46 PM, David Waite via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 20, 2016, at 10:17 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

So silently using the type implementor’s bar() method when using Foo is unacceptable. You don’t know if it meets the requirements, because Foo never specified requirements for a bar() method.

BTW, it would also be dangerous to let an extension make a protocol implement another protocol for similar reasons.

So, options to solve:
- Having the extension to protocol Foo only apply when dealing in terms of Foo type and not the implementors type. This sounds less useful than what we have today.
- You could have a warning if the compiler sees a Foo extension and a Foo implementation both with bar(). Hopefully the application developer has control over either the protocol definition, the extension, or the implementation of the protocol to try and resolve it.
- forbid protocol extensions adding methods - they can only implement existing methods
- If protocol implementations used “override” (or perhaps a better named keyword for covering this instance as well like “implement”), you could consider protocol extensions to extend the protocol definition more safely. You would also catch the case where the Protocol definition changed to include the same foo() method the implementing type defined independently, so the implementor can make sure their version of foo() meets the requirements the protocol gives.

-DW

On May 20, 2016, at 5:56 AM, Fabian Ehrentraud via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi,

there's been a little discussion about static vs. dynamic dispatch on this mailing list, and there is a good post about the pitfalls when using attributes defined in extensions [1].

Having run into this myself during development, is there a plan on how to reduce the pitfalls in future versions of Swift?

- Fabian

[1] IBM Developer

Sorry, I understand and appreciate your pragmatism. Right now it feels very much like a fight to the ideological death between POP and OOP and it may get really bad results this way.

Sent from my iPhone

On 4 Mar 2016, at 08:58, Brent Royal-Gordon <brent at architechies.com <https://lists.swift.org/mailman/listinfo/swift-evolution&gt;&gt; wrote:

>> Brent, why is dynamic dispatching for protocol extension default implementations wrong in your mind? Wouldn't you agree that when static dispatching introduces such a side effect that it should not be automatically applied and perhaps a keyword should be added if you really wanted static dispatching nonetheless?
>>
>> I think that code execution should not be affected by type casting, it feels like a very confusing part of the language.
>
> I don't think dynamic dispatch is wrong; I think it's a large and technically challenging change. So in the spirit of incrementalism, I was trying to make cautious proposals which kept existing semantics intact but made them clearer, in preparation for perhaps eventually introducing dynamic dispatch. (Basically, I suggested that non-overridable protocol extension members should be marked `final` and it should be illegal to shadow them.)
>
> But the feedback I got indicated that most people wanted a more aggressive proposal which introduced dynamic dispatch immediately. That's much harder to propose because it touches on all sorts of runtime implementation details I know nothing about, so I didn't try to draft a proposal.
>
> (You are, perhaps inadvertently, currently demonstrating exactly what happened in those previous threads!)
>
> --
> Brent Royal-Gordon
> Architechies
>

> On Dec 11, 2015, at 8:56 PM, Kevin Ballard via swift-evolution <swift-evolution at swift.org <https://lists.swift.org/mailman/listinfo/swift-evolution&gt;&gt; wrote:
>
> You think that Swift prefers virtual dispatch. I think it prefers static.
>
> I think what's really going on here is that _in most cases_ there's no observable difference between static dispatch and virtual dispatch. If you think of Swift as an OOP language with a powerful value-typed system added on, then you'll probably think Swift prefers virtual dispatch. If you think of Swift as a value-typed language with an OOP layer added, then you'll probably think Swift prefers static dispatch. In reality, Swift is a hybrid language and it uses different types of dispatch in different situations as appropriate.

(emphasis mine)

I know that this is a bit philosophical, but let me suggest a “next level down” way to look at this. Static and dynamic are *both* great after all, and if you’re looking to type-cast languages, you need to consider them both in light of their semantics, but also factor in their compilation strategy and the programmer model that they all provide. Let me give you some examples, but keep in mind that this is a narrow view and just MHO:

1. C: Static compilation model, static semantics. While it does provide indirect function pointers, C does everything possible to punish their use (ever see the non-typedef'd prototype for signal(3/7)?), and is almost always statically compiled. It provides a very “static centric” programming model. This is great in terms of predictability - it makes it trivial to “predict” what your code will look like at a machine level.

2. Javascript: Completely dynamic compilation model, completely dynamic semantics. No one talks about statically compiling javascript, because the result of doing so would be a really really slow executable. Javascript performance hinges on dynamic profile information to be able to efficiently execute a program. This provides a very “dynamic centric” programming model, with no ability to understand how your code executes at a machine level.

3. C++: C++ is a step up from C in terms of introducing dynamism into the model with virtual functions. Sadly, C++ also provides a hostile model for static optimizability - the existence of placement new prevents a lot of interesting devirtualization opportunities, and generally makes the compiler’s life difficult. OTOH, like C, C++ provides a very predictable model: C++ programmers assume that C constructs are static, but virtual methods will be dynamically dispatched. This is correct because (except for narrow cases) the compiler has to use dynamic dispatch for C++ virtual methods. The good news here is that its dynamism is completely opt in, so C++ preserves all of the predictability, performance, and static-compilability of C while providing a higher level programming model. If virtual methods are ever actually a performance problem, a C++ programmer has ways to deal with that, directly in their code.

4. Java: Java makes nearly "everything" an object (no structs or other non-primitive value types), and all methods default to being “virtual” (in the C++ sense). Java also introduces interfaces, which offer an added dimension on dynamic dispatch. To cope with this, Java assumes a JIT compilation model, which can use dynamic behavior to de-virtualize the (almost always) monomorphic calls into checked direct calls. This works out really well in practice, because JIT compilers are great at telling when a program with apparently very dynamic semantics actually have static semantics in practice (e.g. a dynamic call has a single receiver). OTOH, since the compilation model assumes a JIT, this means that purely “AOT” static compilers (which have no profile information, no knowledge of class loaders, etc) necessarily produce inferior code. It also means that Java doesn’t “scale down” well to small embedded systems that can’t support a JIT, like a bootloader.

5) Objective-C: Objective-C provides a hybrid model which favors predictability due to its static compilation model (similar in some ways to C++). The C-like constructs provide C-like performance, and the “messaging” constructs are never “devirtualized”, so they provide very predictable performance characteristics. Because it is predictable, if the cost of a message send ever becomes an issue in practice, the programmer has many patterns to deal with it (including "imp caching", and also including the ability to define the problem away by rewriting code in terms of C constructs). The end result of this is that programmers write code which use C-level features where performance matters and dynamicism doesn’t, but use ObjC features where dynamicism is important or where performance doesn’t matter.

While it would be possible to implement a JIT compiler for ObjC, I’d expect the wins to be low, because the “hot” code which may be hinging on these dynamic features is likely to already be optimized by hand.

6) GoLang: From this narrow discussion and perspective, Go has a hybrid model that has similar characteristics to Objective-C 2013 (which introduced modules, but didn’t yet have generics). It assumes static compilation and provides a very predictable hybrid programming model. Its func’s are statically dispatched, but its interfaces are dynamically dispatched. It doesn’t provide guaranteed dynamic dispatch (or “classes") like ObjC, but it provides even more dynamic feautres in other areas (e.g. it requires a cycle-collecting garbage collector). Its "interface{}” type is pretty equivalent to “id” (e.g. all uses of it are dynamically dispatched or must be downcasted), and it encourages use of it in the same places that Objective-C does. Go introduces checked downcasts, which introduce some run-time overhead, but also provide safety compared to Objective-C. Go thankfully introduces a replacement for the imperative constructs in C, which defines away a bunch of C problems that Objective-C inherited, and it certainly is prettier!

… I can go on about other languages, but I have probably already gotten myself into enough trouble. :-)

With this as context, lets talk about Swift:

Swift is another case of a hybrid model: its semantics provide predictability between obviously static (structs, enums, and global funcs) and obviously dynamic (classes, protocols, and closures) constructs. A focus of Swift (like Java and Javascript) is to provide an apparently simple programming model. However, Swift also intentionally "cheats" in its global design by mixing in a few tricks to make the dynamic parts of the language optimizable by a static compiler in many common cases, without requiring profiling or other dynamic information.. For example, the Swift compiler can tell if methods in non-public classes are never overridden (and non-public is the default, for a lot of good reasons) - thus treating them as final. This allows eliminating much of the overhead of dynamic dispatch without requiring a JIT. Consider an “app”: because it never needs to have non-public classes, this is incredibly powerful - the design of the swift package manager extends this even further (in principle, not done yet) to external libraries. Further, Swift’s generics provide an a static performance model similar to C++ templates in release builds (though I agree we need to do more to really follow through on this) -- while Swift existentials (values of protocol type) provide a balance by giving a highly dynamic model.

The upshot of this is that Swift isn’t squarely in either of the static or dynamic camps: it aims to provide a very predictable performance model (someone writing a bootloader or firmware can stick to using Swift structs and have a simple guarantee of no dynamic overhead or runtime dependence) while also providing an expressive and clean high level programming model - simplifying learning and the common case where programmers don’t care to count cycles. If anything, I’d say that Swift is an “opportunistic” language, in that it provides a very dynamic “default" programming model, where you don’t have to think about the fact that a static compiler is able to transparently provide great performance - without needing the overhead of a JIT.

Finally, while it is possible that a JIT compiler might be interesting someday in the Swift space, if we do things right, it will never be “worth it” because programmers will have enough ability to reason about performance at their fingertips. This means that there should be no Java or Javascript-magnitude "performance delta" sitting on the table waiting for a JIT to scoop up. We’ll see how it works out long term, but I think we’re doing pretty well so far.

TL;DR: What I’m really getting at is that the old static vs dynamic trope is at the very least only half of the story. You really need to include the compilation model and thus the resultant programmer model into the story, and the programmer model is what really matters, IMHO.

-Chris

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

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

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

Because I think the dynamic case is what most people expect and should be the default. The unexpected behavior should be the opt in behavior as you know what you are doing at this point. At least this is my reasoning

Brandon

···

On May 20, 2016, at 1:39 PM, Krystof Vasa via swift-evolution <swift-evolution@swift.org> wrote:

How about the other way around, allowing something like this, explicitly specifying the dynamic nature of the function, thus forcing the dynamic dispatch?

protocol MyProtocol { }

extension MyProtocol {
  dynamic func getInt() -> Int {
    return 0
  }
}

Krystof

I don’t think that would fly :-). That said, has anyone considered requiring a keyword on the method in the protocol extension that makes it explicit that the dispatch is non-dynamic?

-Chris
_______________________________________________
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

That said, has anyone considered requiring a keyword on the method in the protocol extension that makes it explicit that the dispatch is non-dynamic?

Many moons ago, I was pushing to require a `final` keyword on protocol extension methods, which would prevent conforming types from providing their own implementations. It was probably the first thing I worked on. There were long arguments about whether and how you could override the `final`-ness, people kept clamoring for dynamic dispatch, and I ultimately wasn't able to produce a consensus before I had to turn my attention back towards paying work.

I agree a keyword here might be useful, but I'm not sure 'final' is the right choice. The problem with this is that they aren't exactly 'final'. They can be shadowed by conforming types when the static type of an instance is the concrete type. Disallowing shadowing by the concrete type is problematic in a number of ways (retroactive modeling, openness of protocol extensions, etc).

···

Sent from my iPad
On May 21, 2016, at 6:42 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

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

Hi all,

I unsuccessfully tried to start a thread about this topic as well, 14 hours earlier ( [swift-evolution] static vs. dynamic dispatch of protocol methods ).

I think what is needed is that every method that wants to override something has to be annotated with an `override` keyword. And it is not enough to have just one `override`: you need `override` for overriding from a class, `override(Pr)` for overriding from protocol `Pr`, and overriding a method which is not defined in any protocol or superclass (but just in a protocol extension), is just impossible (yet). Everything else is impractical.

The idea is that each method has a contract. When sending a message, the most specialized method that implements the contract of that message should get called. But conceptually, messages and contracts are not the same, and they will never be. The same message can define different contracts for different classes. Two methods can be called by the same message but have a different contract (on two different objects, of course). A proposal has to deal with this somehow.

`override` is a "contract-annotation": it says "this method has the same contract as the method defined in the superclass (subtext: I will not violate LSP)"

1) Dispatching everything dynamically is bad,
2) dispatching everything statically is bad,
3) having the caller decide is bad too. (just see my code example on 1) and replace the statically dispatched call to `makeBlue` with `@dynamicDispatch(makeBlue)`. We see: the program misbehaves, but why was the dynamicDispatch-decision of the caller bad here?)
4) The person who writes a method should know it's contract. This developer can also decide if it matches another contract from a protocol and if it therefore should be an override.

I think the sticking point here is to think through realistic examples, not short use-cases with a few lines of code; but 2 or 3 modules with multiple protocols, extensions, classes and overrides. Maybe my original mail was incomprehensible. But it at least tries not to oversimplify the problem when designing a solution.

-Michael

···

Am 20.05.2016 um 21:51 schrieb Fabian Ehrentraud via swift-evolution <swift-evolution@swift.org>:

Sorry, I understand and appreciate your pragmatism. Right now it feels
very much like a fight to the ideological death between POP and OOP
and it may get really bad results this way.

Being in the run-up to WWDC, I don't really have the time to participate
in this discussion right now, although I think it is important and
interesting. However, this last sentence caught my eye and I thought I
should clarify something: protocols unify static and dynamic dispatch,
and one is not inherently better than the other. They have different
strengths. Protocol-oriented programming is about leveraging those
strengths appropriately, not about a mandate to choose one or the other
form of dispatch.

Well said.
Maybe the issue is not about being unclear at the point of definition in the extension, but at the call site - similar to value vs. reference semantics.
Just as a thought experiment, putting aside that it would be ugly, would having a different syntax for invoking methods with static and dynamic dispatch help to understand the working of the code better?

Making them final is not a good idea. I see the default implementations in protocols as something that should replace the optional methods in @objc protocols. Example - a delegate protocol for table view (either UITableView or NSTableView): How would you represent it in pure non-@objc Swift? If it was a regular protocol, you'd need to implement all the methods.

With default implementations, the default implementation returns a default value and you don't need to implement this method from the protocol.

You might argue that you mean just the methods declared only in the protocol extension - I see those, however as something that may help subclassing delegated instances. Example:

You have a root class representing some kind of a view - it has a `delegate` property. Then you decide to make a subclass and would like to introduce your own delegate methods on top of those offered by the superclass.

You can subclass the protocol, but Swift won't let you override the `delegate` property with a different type. So you can create a new property `mySubclassDelegate`, which is horrid, but kinda works.

The other option is to simply extend the original delegate protocol with additional methods with default implementation, which you should be able to override in your conforming class.

In code example:

protocol Delegate {
  func myClassDidSomething(obj: MyClass)
}

class MyClass {
  weak var delegate: Delegate?
}

extension Delegate {
  func mySubclassDidSomethingElse(obj: MySubclass) { }
}

class MySubclass: MyClass { }

This is where I see how this can be very useful in many areas not having it final.

Charlie

···

Many moons ago, I was pushing to require a `final` keyword on protocol extension methods, which would prevent conforming types from providing their own implementations. It was probably the first thing I worked on. There were long arguments about whether and how you could override the `final`-ness, people kept clamoring for dynamic dispatch, and I ultimately wasn't able to produce a consensus before I had to turn my attention back towards paying work.

--
Brent Royal-Gordon
Architechies

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

Making them final is not a good idea. I see the default implementations in protocols as something that should replace the optional methods in @objc protocols.

We aren't discussing default implementations. We're discussing methods that are listed *only* in the protocol extension, not in the protocol itself. These methods cannot be "overridden" in the way that a defaulted protocol method can be; I think it's safest to outlaw any attempt to "override" them at all.

···

--
Brent Royal-Gordon
Architechies

Making them final is not a good idea. I see the default implementations in protocols as something that should replace the optional methods in @objc protocols. Example - a delegate protocol for table view (either UITableView or NSTableView): How would you represent it in pure non-@objc Swift? If it was a regular protocol, you'd need to implement all the methods.

With default implementations, the default implementation returns a default value and you don't need to implement this method from the protocol.

This thread isn't default implementations of protocol requirements. Those are dynamically dispatched. This thread is about *new* methods introduced in protocol extensions. These are not dynamically dispatched and exhibit different behavior depending on the static type due to the shadowing issue.

···

Sent from my iPad

On May 21, 2016, at 7:05 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

You might argue that you mean just the methods declared only in the protocol extension - I see those, however as something that may help subclassing delegated instances. Example:

You have a root class representing some kind of a view - it has a `delegate` property. Then you decide to make a subclass and would like to introduce your own delegate methods on top of those offered by the superclass.

You can subclass the protocol, but Swift won't let you override the `delegate` property with a different type. So you can create a new property `mySubclassDelegate`, which is horrid, but kinda works.

The other option is to simply extend the original delegate protocol with additional methods with default implementation, which you should be able to override in your conforming class.

In code example:

protocol Delegate {
   func myClassDidSomething(obj: MyClass)
}

class MyClass {
   weak var delegate: Delegate?
}

extension Delegate {
   func mySubclassDidSomethingElse(obj: MySubclass) { }
}

class MySubclass: MyClass { }

This is where I see how this can be very useful in many areas not having it final.

Charlie

Many moons ago, I was pushing to require a `final` keyword on protocol extension methods, which would prevent conforming types from providing their own implementations. It was probably the first thing I worked on. There were long arguments about whether and how you could override the `final`-ness, people kept clamoring for dynamic dispatch, and I ultimately wasn't able to produce a consensus before I had to turn my attention back towards paying work.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

Adding code to what really always sounded to me like pure interfaces/API contracts decoupling functionality from concrete implementation does bring its fair share of headaches, but in your experience is it really something delivering big upsides?
I do agree that in both Swift and Java the code in protocols/interfaces ship has long sailed so it is a moot point.

···

Sent from my iPhone

On 21 May 2016, at 13:25, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Making them final is not a good idea. I see the default implementations in protocols as something that should replace the optional methods in @objc protocols.

We aren't discussing default implementations. We're discussing methods that are listed *only* in the protocol extension, not in the protocol itself. These methods cannot be "overridden" in the way that a defaulted protocol method can be; I think it's safest to outlaw any attempt to "override" them at all.

--
Brent Royal-Gordon
Architechies

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

Yes, see below. I believe it should work as sketched below. Making the extension default implementations final will prevent from extending the delegate protocols by subclasses (and much more).

IMHO the default dispatch for methods on protocol extensions should be dynamic.

···

This thread isn't default implementations of protocol requirements. Those are dynamically dispatched. This thread is about *new* methods introduced in protocol extensions. These are not dynamically dispatched and exhibit different behavior depending on the static type due to the shadowing issue.

You might argue that you mean just the methods declared only in the protocol extension - I see those, however as something that may help subclassing delegated instances. Example:

You have a root class representing some kind of a view - it has a `delegate` property. Then you decide to make a subclass and would like to introduce your own delegate methods on top of those offered by the superclass.

You can subclass the protocol, but Swift won't let you override the `delegate` property with a different type. So you can create a new property `mySubclassDelegate`, which is horrid, but kinda works.

The other option is to simply extend the original delegate protocol with additional methods with default implementation, which you should be able to override in your conforming class.

In code example:

protocol Delegate {
  func myClassDidSomething(obj: MyClass)
}

class MyClass {
  weak var delegate: Delegate?
}

extension Delegate {
  func mySubclassDidSomethingElse(obj: MySubclass) { }
}

class MySubclass: MyClass { }

This is where I see how this can be very useful in many areas not having it final.

Charlie

Many moons ago, I was pushing to require a `final` keyword on protocol extension methods, which would prevent conforming types from providing their own implementations. It was probably the first thing I worked on. There were long arguments about whether and how you could override the `final`-ness, people kept clamoring for dynamic dispatch, and I ultimately wasn't able to produce a consensus before I had to turn my attention back towards paying work.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

See the text below the quoted paragraph in my email - I've mentioned how extending the protocol can be helpful e.g. in case of delegate protocols - where you may want to extend the protocol in subclasses of the delegated class introducing new methods for the delegate. In such scenarios, forcing them final is not an option.

···

21. 5. 2016 v 14:25, Brent Royal-Gordon <brent@architechies.com>:

Making them final is not a good idea. I see the default implementations in protocols as something that should replace the optional methods in @objc protocols.

We aren't discussing default implementations. We're discussing methods that are listed *only* in the protocol extension, not in the protocol itself. These methods cannot be "overridden" in the way that a defaulted protocol method can be; I think it's safest to outlaw any attempt to "override" them at all.

--
Brent Royal-Gordon
Architechies

Yes, see below. I believe it should work as sketched below. Making the extension default implementations final will prevent from extending the delegate protocols by subclasses (and much more).

IMHO the default dispatch for methods on protocol extensions should be dynamic.

This has been discussed extensively and is problematic for a number of reasons.

···

Sent from my iPad

On May 21, 2016, at 7:17 AM, Charlie Monroe <charlie@charliemonroe.net> wrote:

This thread isn't default implementations of protocol requirements. Those are dynamically dispatched. This thread is about *new* methods introduced in protocol extensions. These are not dynamically dispatched and exhibit different behavior depending on the static type due to the shadowing issue.

You might argue that you mean just the methods declared only in the protocol extension - I see those, however as something that may help subclassing delegated instances. Example:

You have a root class representing some kind of a view - it has a `delegate` property. Then you decide to make a subclass and would like to introduce your own delegate methods on top of those offered by the superclass.

You can subclass the protocol, but Swift won't let you override the `delegate` property with a different type. So you can create a new property `mySubclassDelegate`, which is horrid, but kinda works.

The other option is to simply extend the original delegate protocol with additional methods with default implementation, which you should be able to override in your conforming class.

In code example:

protocol Delegate {
func myClassDidSomething(obj: MyClass)
}

class MyClass {
weak var delegate: Delegate?
}

extension Delegate {
func mySubclassDidSomethingElse(obj: MySubclass) { }
}

class MySubclass: MyClass { }

This is where I see how this can be very useful in many areas not having it final.

Charlie

Many moons ago, I was pushing to require a `final` keyword on protocol extension methods, which would prevent conforming types from providing their own implementations. It was probably the first thing I worked on. There were long arguments about whether and how you could override the `final`-ness, people kept clamoring for dynamic dispatch, and I ultimately wasn't able to produce a consensus before I had to turn my attention back towards paying work.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

See the text below the quoted paragraph in my email - I've mentioned how extending the protocol can be helpful e.g. in case of delegate protocols - where you may want to extend the protocol in subclasses of the delegated class introducing new methods for the delegate. In such scenarios, forcing them final is not an option.

Nobody is talking about forcing them final. We are talking about annotating them with a keyword that documents their behavior (which is unintuitive for sure but makes sense when you think through how things work behind the scenes).

Maybe we will figure out a way to have something better in the future, but until then highlighting the behavior via annotation is a pretty good option.

···

Sent from my iPad

On May 21, 2016, at 8:03 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

21. 5. 2016 v 14:25, Brent Royal-Gordon <brent@architechies.com>:

Making them final is not a good idea. I see the default implementations in protocols as something that should replace the optional methods in @objc protocols.

We aren't discussing default implementations. We're discussing methods that are listed *only* in the protocol extension, not in the protocol itself. These methods cannot be "overridden" in the way that a defaulted protocol method can be; I think it's safest to outlaw any attempt to "override" them at all.

--
Brent Royal-Gordon
Architechies

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

I was responding to Brent's mail:

Many moons ago, I was pushing to require a `final` keyword on protocol extension methods, which would prevent conforming types from providing their own implementations.

Where was proposed to force them to be final and was just trying to provide an example in which the conforming class may want to override them, so forcing them final isn't a good idea. Sorry about the confusion. I'm generally in favor of a modifier rather than annotation, e.g.

dynamic func myFunc()
nondynamic func myFunc()

Dynamic now being just for vars, so perhaps extending it to functions.

···

21. 5. 2016 v 15:27, Matthew Johnson <matthew@anandabits.com>:

Sent from my iPad

On May 21, 2016, at 8:03 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

See the text below the quoted paragraph in my email - I've mentioned how extending the protocol can be helpful e.g. in case of delegate protocols - where you may want to extend the protocol in subclasses of the delegated class introducing new methods for the delegate. In such scenarios, forcing them final is not an option.

Nobody is talking about forcing them final. We are talking about annotating them with a keyword that documents their behavior (which is unintuitive for sure but makes sense when you think through how things work behind the scenes).

Maybe we will figure out a way to have something better in the future, but until then highlighting the behavior via annotation is a pretty good option.

21. 5. 2016 v 14:25, Brent Royal-Gordon <brent@architechies.com>:

Making them final is not a good idea. I see the default implementations in protocols as something that should replace the optional methods in @objc protocols.

We aren't discussing default implementations. We're discussing methods that are listed *only* in the protocol extension, not in the protocol itself. These methods cannot be "overridden" in the way that a defaulted protocol method can be; I think it's safest to outlaw any attempt to "override" them at all.

--
Brent Royal-Gordon
Architechies

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

I support *at least* to introduce such a special marker for method declared *only* in protocol extension (no declaration for it in protocol itself) to make it clear that it will be dispatched statically.
Probably right now I support `nondynamic`.

But, there is question regarding another situation when the protocol method dispatched *statically* even if *defined* in protocol declaration:

protocol A {
     func f()
     func x()
}

extension A {
     func x() {print("a-x")}
}

class B: A { // already strange. B depends on A extension. did not implement all required methods from A
     func f() {}
}

class C: B {
     func x(){print("c-x")}
}

var c : A = C()
c.x() // "a-x". but C() *implements* x() that *is* defined in protocol

IMO this is totally unexpected and must be dispatched dynamically. I believe that there can not be any explanation why this is correct: A - is a protocol, C - is a class conformed to A protocol and implemented all methods of that protocol.

It is clear, that you don't want to decorate A.x() with such `nondynamic` as if it was implemented in B - it will be dynamic:

class B: A {
     func f() {}
     func x(){print("b-x")}
}

var b : A = B()
b.x() // "b-x". now dynamic

So, again, IMO at least we need to decorate protocol extension methods that was not defined in protocol itself, but the 'issue' is bigger 'than just this.

···

On 21.05.2016 16:27, Matthew Johnson via swift-evolution wrote:

Nobody is talking about forcing them final. We are talking about
annotating them with a keyword that documents their behavior (which is
unintuitive for sure but makes sense when you think through how things
work behind the scenes).

Maybe we will figure out a way to have something better in the future,
but until then highlighting the behavior via annotation is a pretty good
option.

I was responding to Brent's mail:

Many moons ago, I was pushing to require a `final` keyword on protocol extension methods, which would prevent conforming types from providing their own implementations.

Where was proposed to force them to be final and was just trying to provide an example in which the conforming class may want to override them, so forcing them final isn't a good idea.

Again, nobody ever proposed forcing them final. The proposal was to use final as a way to document the existing behavior.

You and many others are asking for a new option of dynamic dispatch of protocol extensions. We may see this someday but it is not going to happen in Swift 3.

Sorry about the confusion. I'm generally in favor of a modifier rather than annotation, e.g.

dynamic func myFunc()
nondynamic func myFunc()

Dynamic now being just for vars, so perhaps extending it to functions.

By annotation I just meant something indicating behavior. Your 'nondynamic' qualifies, but is not the right term.

'dynamic' in Swift does not just mean dynamic dispatch semantics. It means always dispatched through the Objective-C runtime. If it didn't already have this meaning I would probably like 'nondynamic' quite a bit as a more precise alternative.

···

Sent from my iPad

On May 21, 2016, at 8:56 AM, Charlie Monroe <charlie@charliemonroe.net> wrote:

21. 5. 2016 v 15:27, Matthew Johnson <matthew@anandabits.com>:

Sent from my iPad

On May 21, 2016, at 8:03 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

See the text below the quoted paragraph in my email - I've mentioned how extending the protocol can be helpful e.g. in case of delegate protocols - where you may want to extend the protocol in subclasses of the delegated class introducing new methods for the delegate. In such scenarios, forcing them final is not an option.

Nobody is talking about forcing them final. We are talking about annotating them with a keyword that documents their behavior (which is unintuitive for sure but makes sense when you think through how things work behind the scenes).

Maybe we will figure out a way to have something better in the future, but until then highlighting the behavior via annotation is a pretty good option.

21. 5. 2016 v 14:25, Brent Royal-Gordon <brent@architechies.com>:

Making them final is not a good idea. I see the default implementations in protocols as something that should replace the optional methods in @objc protocols.

We aren't discussing default implementations. We're discussing methods that are listed *only* in the protocol extension, not in the protocol itself. These methods cannot be "overridden" in the way that a defaulted protocol method can be; I think it's safest to outlaw any attempt to "override" them at all.

--
Brent Royal-Gordon
Architechies

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

Where was proposed to force them to be final and was just trying to provide an example in which the conforming class may want to override them, so forcing them final isn't a good idea.

Again, nobody ever proposed forcing them final. The proposal was to use final as a way to document the existing behavior.

I *did* propose forcing them final, and I'm still very skeptical that a `nondynamic` keyword that does nothing when you shadow the method is a good idea. People are still going to naïvely try to override these methods and be surprised when it doesn't work. A `nondynamic` keyword at the original declaration site will help them understand what happened when they're investigating the bug, but it still seems like this kind of code is so suspect that Swift ought to flag it from the start.

···

--
Brent Royal-Gordon
Architechies

Where was proposed to force them to be final and was just trying to provide an example in which the conforming class may want to override them, so forcing them final isn't a good idea.

Again, nobody ever proposed forcing them final. The proposal was to use final as a way to document the existing behavior.

I *did* propose forcing them final, and I'm still very skeptical that a `nondynamic` keyword that does nothing when you shadow the method is a good idea. People are still going to naïvely try to override these methods and be surprised when it doesn't work. A `nondynamic` keyword at the original declaration site will help them understand what happened when they're investigating the bug, but it still seems like this kind of code is so suspect that Swift ought to flag it from the start.

Sorry about that. Either I didn't see that or I forgot about it. Making them 'final' causes problems with retroactive modeling. There are other issues as well but that is the most significant one.

···

Sent from my iPad
On May 21, 2016, at 3:16 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Brent Royal-Gordon
Architechies