> On May 20, 2016, at 11:17 AM, Austin Zheng via swift-evolution > <[email protected]> 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.
That would prevent us from adding extension methods to protocols declared in modules we depend on. This is way to useful to throw away. > > Austin > >> On May 20, 2016, at 5:56 AM, Fabian Ehrentraud via swift-evolution >> <[email protected] <mailto:[email protected]>> 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] >> https://developer.ibm.com/swift/2016/01/27/seven-swift-snares-how-to-avoid-them/ >> >> <https://developer.ibm.com/swift/2016/01/27/seven-swift-snares-how-to-avoid-them/> >> >>> 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>> 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>> 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 >> [email protected] <mailto:[email protected]> >> https://lists.swift.org/mailman/listinfo/swift-evolution > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
