[swift-evolution] Static Dispatch Pitfalls
michael.peternell at gmx.at
Sat May 21 03:40:34 CDT 2016
> Am 20.05.2016 um 21:51 schrieb Fabian Ehrentraud via swift-evolution <swift-evolution at 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?
I unsuccessfully tried to start a thread about this topic as well, 14 hours earlier ( https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160516/018214.html ).
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.
More information about the swift-evolution