[swift-evolution] Proposal: Universal dynamic dispatch for method calls

ilya ilya.nikokoshev at gmail.com
Mon Dec 7 17:04:46 CST 2015


On Tuesday, December 8, 2015, Paul Cantrell via swift-evolution <
swift-evolution at swift.org> wrote:

> > The ability to use static dispatch in most cases is one of the great
> features of Swift, and it's something that needs to be preserved, not
> relegated to being an optimization that can be done occasionally.
>
> Can you think of a situation where that’s the desired semantics, as
> opposed to either a desirable optimization or a confusing workaround for
> the “monkey collision” problem? (I can’t see the use case, but I’m open to
> hearing it!)
>
>
Sure, private protocol extension. For example,

public protocol Animal {
  func greet()
  func sit()
  func run()
}

private extension Animal {
  func compete() { greet(); sit(); run()}
}

// we are provided with animal
... animal.compete()...


> It's also worth noting that the current behavior, where methods defined
> in protocol extensions can't be overridden by the implementing type, may
> actually be the desired behavior in many cases.
>
> If you don’t want a method to be overridable, that’s what “final” is for.
>
> The current behavior, in which a method is silently shadowed, does not
> seem to be to be a desirable behavior in any situation. The compiler
> warnings/errors Joe Groff proposed seem like a bare minimum, but I’d prefer
> to eliminate the situation that needs to be warned about in the first place.
>
> Cheers, P
>
> > On Dec 7, 2015, at 4:11 PM, Kevin Ballard via swift-evolution <
> swift-evolution at swift.org <javascript:;>> wrote:
> >
> > I'd love to see these two key things that Joe mentioned get added.
> > Diagnostics around confusing situations is a good idea (although there
> > needs to be a way to disable it too; what if I intentionally need to use
> > the same name in a type and in an extension to one of the conformed-to
> > protocols, for various reasons?).
> >
> > I can't support the original proposal though, of making foo.bar() use
> > dynamic dispatch. The ability to use static dispatch in most cases is
> > one of the great features of Swift, and it's something that needs to be
> > preserved, not relegated to being an optimization that can be done
> > occasionally.
> >
> > It's also worth noting that the current behavior, where methods defined
> > in protocol extensions can't be overridden by the implementing type, may
> > actually be the desired behavior in many cases. Heck, the ability to
> > trigger this different behavior is one of the three reasons to even
> > define methods in protocol extensions instead of in the protocol (the
> > others being when you're defining it for a subset of protocol
> > implementations, and when you're defining extensions on protocols
> > imported from other modules). Removing this functionality (by making
> > foo.bar() always dynamic) means reverting back to the Swift 1.x
> > convention of having global functions to provide this behavior.
> >
> > I wouldn't mind seeing something like the `dynamic` keyword to allow
> > concrete types to override these protocol extension methods (although
> > `dynamic` in this case would not imply @objc, like it does today, which
> > may be a little confusing), but that would be opt-in behavior.
> >
> > -Kevin Ballard
> >
> > On Mon, Dec 7, 2015, at 12:14 PM, Joe Groff via swift-evolution wrote:
> >> The main reason to constrain dynamic dispatch is modularity. The
> problems
> >> of interfering categories or monkey-patches in languages like ObjC and
> >> Ruby with late-bound dispatch and open classes are well-known. In
> Swift's
> >> model, it isn't possible for an extension in one module to interfere
> with
> >> existing protocol conformances or class hierarchies at runtime (except
> >> with @objc of course). Modules need to be compiled together to be aware
> >> of each other to interact with each other's interfaces.
> >>
> >> The particular example Alexandros brings up is more an artifact of our
> >> existing implementation than desirable behavior. Two key things are
> >> missing:
> >>
> >> - the ability for extensions to protocols to add new
> >> dynamically-dispatched methods, and
> >> - compiler quality work to diagnose confusing cases where concrete types
> >> obviously shadow non-dynamic protocol extensions.
> >>
> >> There is a related behavior change proposal Doug Gregor's been working
> on
> >> for classes, to have conforming to a protocol implicitly re-declare all
> >> the protocol's methods as class methods, so that they can be overridden
> >> by subclasses in the expected way.
> >>
> >> -Joe
> >>
> >>> On Dec 6, 2015, at 8:17 PM, Paul Cantrell via swift-evolution <
> swift-evolution at swift.org <javascript:;>> wrote:
> >>>
> >>> One of the few things in Swift 2 that feels to me like a design flaw
> is the way Swift mixes static and dynamic method dispatch.
> >>>
> >>> Alexandros Salazar gives an excellent explanation of this problem —
> and I agree wholeheartedly with his title for the article:
> >>>
> >>>  http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future
> >>>
> >>> The upshot is that when we see this:
> >>>
> >>>  foo.bar()
> >>>
> >>> …it’s very hard to know how the compiler will determine which
> implementation of bar() to use. It might use static dispatch; it might use
> dynamic dispatch.
> >>>
> >>> The rules that govern this are arcane, and hard to remember. They have
> the feeling of being a “gotcha” question for job interviews — always a red
> flag for language features.
> >>>
> >>> Even if you remember the rules, the information needed to determine
> whether dispatch is static or dynamic is hard to track down. It depends on
> whether bar()’s implementation comes from an extension, whether the
> extension method appeared on the extended protocol, and whether the
> inferred type of foo is the protocol itself or an implementing type.
> >>>
> >>> A crucial part of the meaning of “foo.bar()” is implicit, and hard to
> determine. This runs contrary to Swift’s stated goal of prioritizing
> clarity at the point of API use, and its general pattern of making intent
> explicit. And it feels dangerous — a wellspring of insidious bugs.
> >>>
> >>> Thus:
> >>>
> >>>
> >>> PROPOSAL
> >>>
> >>> Make the syntax “foo.bar()” always use dynamic dispatch, i.e. always
> use _only_ the runtime type of foo to determine which implementation of
> bar() to use. If an extension method collision occurs when a type
> implements multiple protocols, require the type to explicitly specify which
> one to use (as Swift already requires the caller to do at the point of
> invocation).
> >>>
> >>>
> >>> I mean this proposal somewhat as a strawman. It’s such an obvious
> choice, I’m sure there were good reasons not to do it. But I’d like to
> propose the obvious solution in order to understand what’s wrong with it. I
> realize static dispatch precludes some optimizations, but I doubt that this
> alone drove the design choice. I see no safety or expressiveness upside to
> the way it works now.
> >>>
> >>> Cheers,
> >>>
> >>> Paul
> >>>
> >>> _______________________________________________
> >>> swift-evolution mailing list
> >>> swift-evolution at swift.org <javascript:;>
> >>> https://lists.swift.org/mailman/listinfo/swift-evolution
> >>
> >> _______________________________________________
> >> swift-evolution mailing list
> >> swift-evolution at swift.org <javascript:;>
> >> https://lists.swift.org/mailman/listinfo/swift-evolution
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org <javascript:;>
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org <javascript:;>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151208/04079c06/attachment.html>


More information about the swift-evolution mailing list