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

> On May 20, 2016, at 5:56 AM, Fabian Ehrentraud via swift-evolution 
> <[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]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to