<div dir="ltr">Thanks for that detailed explanation :)<div><br><div>For 1) I'm thinking with Polyfills if Swift were to have them we would ideally need some sort of mixin system. I would love to see a way where we could specify which polyfill to apply like this.</div></div><div><br></div><div>extension CLLocationManager {</div><div><br></div><div>include RequestLocationPolyFill</div><div><br></div><div>}</div><div><br></div><div>or maybe even:</div><div><br></div><div>include CoreLocation apply RequestLocationPolyFill //But not sure about this</div><div><br></div><div>Perhaps if two things tried to polyfill the same thing we would reject the ability to include that polyfill (we sort of have this issue already when two things try to define the same method via an extension.</div><div><br></div><div>I think for 2) as Chris explained above we drop feature detection and for these Polyfills we would try to detect the version for a certain Module. As he states once Swift PM has matured enough it ciuld provide this information. So if I wanted to polyfill requestLocation from the CoreLocation library I could do this:</div><div><br></div><div>@avaliable(CoreLocation, < 9) //Apply to CoreLocation version 9.0 or below (Assuming CoreLocation is versioned same as iOS)</div><div>mixin RequestLocationPolyFill {</div><div> func requestLocation() {</div><div> }</div><div>}</div></div><div class="gmail_extra"><br clear="all"><div><div class="gmail_signature"><div dir="ltr"><div><div dir="ltr">
<p><b><font color="#cc0000">___________________________________</font></b></p><p><b>James⎥Lead Engineer</b></p><p><b><font color="#cc0000"><a href="mailto:james@supmenow.com" target="_blank">james@supmenow.com</a>⎥<a href="http://supmenow.com" target="_blank">supmenow.com</a></font></b></p><p><b><font size="2">Sup</font></b></p><p><b><font size="2">Runway East
</font></b></p><p><b><font size="2">10 Finsbury Square</font></b></p><p><b><font size="2">London</font></b></p><p><b><font size="2">
EC2A 1AF </font></b></p></div></div></div></div></div>
<br><div class="gmail_quote">On Thu, Feb 4, 2016 at 9:04 PM, Devin Coughlin <span dir="ltr"><<a href="mailto:dcoughlin@apple.com" target="_blank">dcoughlin@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">James,<div><br></div><div>We did consider an availability model with feature detection similar to the one you proposed. This is essentially the model that Objective-C has. We’ve found that there are significant drawbacks to that model and believe that version checks + compile-time checking offer a better user experience.</div><div><br></div><div>* Compile-time checking of availability makes version checking less fragile.</div><div><br></div><div>A key component of Swift’s availability model is that — unlike in Objective-C or JavaScript — any use of an API element is verified for availability by the compiler. This eliminates the main source of fragility in the version checking model: getting a version check wrong and calling the API anyway. The compiler makes the strong guarantee that it will detect this and inform the developer that they have made a mistake.</div><div><br></div><div><br></div><div><div>* Feature detection checks are hard to reason about and test.</div><div><br></div><div>With version checks it is is immediately obvious on what environment the code will execute. This makes it easy to reason about, for example, how to test the given class/method/branch. In contrast, with feature detection even determining when a given branch of an availability check will execute requires a trip to the documentation. A polyfill model would make this even more challenging because the feature could be available earlier than the documentation states!</div></div><div><br></div><div><br></div><div>* SPI and direct feature detection. </div><div><br></div><div>Apple sometimes adds features first as SPI and only later makes them available as API, potentially changing behavior when doing so. This means that a naive check for the presence of, say, a class or method, does not necessarily make it safe to call. For example, Apple added UINib as API in iOS 4, but earlier versions used an incompatible class with the same name. In this case, the Objective-C idiom checking for the feature effectively “lied” about UINib’s availability. When it comes to API, the run-time checks for #available need to allow symbols to be present but still not considered available. Version checks (either OS versions or library versions) are one mechanism to do this.</div><div><div><br></div></div><div><br></div><div><div>* Dead check detection</div></div><div><br></div><div>One nice aspect of version checks is that it gives the compiler the ability to detect availability checks that are no longer needed because the application is being deployed only on versions of the OS on which the check would always succeed. This is not possible with a direct feature detection model alone (it still needs APIs to be annotated with their versions) and would help prevent older codebases from being littered with feature checks falling back to effectively dead code that no one knows whether it is safe to remove or not.</div><div><br></div><div><br></div><div>* Overloading makes it verbose to check for a feature.</div><div><br></div><div>Swift’s support for function and method overloads makes it quite verbose to check for existence of a feature. Unambiguously identifying a method in a #available check would require specifying its parameter types and even constraints on generic type parameters.</div><div><br></div><div><br></div><div>* Features are often correlated.</div><div><br></div><div>In Objective-C codebases we find that developers often make implicit assumption about OS versions even when using direct feature checks. For example, a developer will often check for the existence of one method and then perform an unguarded use of another method that was introduced in the same version. With a direct feature detection model, the developer would have to check for each of these features separately — even though they know they were introduced in the same OS version! The fact that Objective-C developers are already skipping checks for correlated features shows that their mental model is already based on versions, so it makes sense to match that model in the affordances exposed by the language.</div><div><br></div><div><br></div><div>All that said, polyfill is a widely used technique and it would be interesting to see what it would take to *safely* integrate into Swift. In my view, the two key challenges there are (1) compatibility (whose polyfill wins when two libraries try to polyfill the same thing?) and (2) how to make assume-guarantee @available() annotations with polyfill/feature detection safe at compile time and efficient without leaking implementation details to clients (we don’t want every function to have to list all the functions it calls [and all the functions they call, etc.] in its @available() annotation!).</div><span class="HOEnZb"><font color="#888888"><div><br></div><div><br></div><div>Devin</div><div><br></div><div><br></div><div><br></div></font></span><div><div><blockquote type="cite"><div><div class="h5"><div>On Feb 2, 2016, at 2:03 AM, James Campbell via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br></div></div><div><div><div class="h5"><div dir="ltr">Coming from a web background (before my iOS career) to me #avaliable has huge problem. It encourages fragility.<div><br></div><div>In my eyes we should encourage two types of detection: Features to make code more adaptable to different environments and language version detection: so we can understand the actual code.</div><div><br></div><div>See this example below:</div><div><br></div><div>func magic(object: Object)</div><div>{</div><div> if(#avaliable(9.0, 10))</div><div> {</div><div> object.foo()</div><div> }</div><div>}</div><div><br></div><div>Ideally for me I would love to check if the foo function exists like so:</div><div><br></div><div><div>func iOS9OnlyProtocolFunction(object: Object)</div><div>{</div><div> if(#avaliable(Object.foo))</div><div> {</div><div> object.foo()</div><div> }</div><div>else </div><div>{</div><div> object.baz()</div><div> }</div><div>}</div><div><br></div><div>I think this encourages feature detection which results in less fragile code. What I would love to do is also to extend this to extensions so we could encourage polyfills.</div><div><br></div><div>extend object where not_avaliable(Object.foo) </div><div>{</div><div> func foo() </div><div> {</div><div> //Polyfill for platforms which don't support the Object.foo method</div><div> }</div><div>}</div><div><br></div><div>Not sure about compiler details but being able to polyfill the function results in much cleaner code for me. I love this approach from the web, so I created my own Objective-C Library to do this:</div><div><br></div><div><a href="https://github.com/jcampbell05/Polly" target="_blank">https://github.com/jcampbell05/Polly</a><br></div><div><div><div dir="ltr"><div><div dir="ltr"><p><b><font color="#cc0000">___________________________________</font></b></p><p><b>James⎥Lead Engineer</b></p><p><b><font color="#cc0000"><a href="mailto:james@supmenow.com" target="_blank">james@supmenow.com</a>⎥<a href="http://supmenow.com/" target="_blank">supmenow.com</a></font></b></p><p><b><font size="2">Sup</font></b></p><p><b><font size="2">Runway East
</font></b></p><p><b><font size="2">10 Finsbury Square</font></b></p><p><b><font size="2">London</font></b></p><p><b><font size="2">
EC2A 1AF </font></b></p></div></div></div></div></div>
</div></div></div></div>
_______________________________________________<span class=""><br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></span></div></blockquote></div><br></div></div></blockquote></div><br></div>