<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Jan 24, 2016, at 11:17 AM, Dave Abrahams via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">on Sat Jan 23 2016, David Owens II <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class=""><blockquote type="cite" class="">I think Joe's reply is a pretty good summary.<br class=""></blockquote><br class="">Hi David,<br class=""><br class="">Let me start by expressing my appreciation for the way you're struggling<br class="">with the hard issues here. The questions you're asking reflect many of<br class="">the same ones we asked ourselves during the development of these<br class="">guidelines.<br class=""><br class=""><blockquote type="cite" class="">At a high-level, I really get no sense on how APIs are really supposed<br class="">to be developed in Swift. Joe talks about second arguments generally<br class="">becoming prepositional phrases, but is that the true intent? Because<br class="">that's not what the guideline says, nor what the language semantics<br class="">really promote or suggest to do.<br class=""></blockquote><br class="">No, that's not the intent of the guideline.<br class=""></div></div></blockquote><div><br class=""></div><div>"The use of external parameter names can allow a function to be called in an expressive, sentence-like manner, while still providing a function body that is readable and clear in intent."</div><div><br class=""></div><div>Source: <a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html" class="">https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html</a></div><div><br class=""></div><div>That's the 2.1 guide, so your mileage may vary in 3.0, but that's some of the baggage coming in to this review.</div><div><br class=""></div><div>The problem I see is that there is a mixed bag of what "good" APIs look like. And when push comes to shove, code wins. The libraries exposed in code, even through the ObjC bridging, will be used as the basis of what determines what good Swift APIs look like more than a published doc.</div><div><br class=""></div><div>However, what I see is the struggle between creating good API call sites, what the defaults of the language provide today, and what the guidelines are saying and comparing those to what we get from the new Swift APIs and the updated ObjC imported APIs.</div><div><br class=""></div><div>By default we get this:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">func max(a: Int, b: Int) -> Int</font></div><div><font face="Menlo" class="">max(a, b: 12)</font></div><div><font face="Menlo" class=""><br class=""></font></div><div><font face="Menlo" class="">func addObserver(observer: Observable, path: String)</font></div><div><font face="Menlo" class="">thing.addObserver(observing, path: "/path/to/observe")</font></div><div><font face="Menlo" class=""><br class=""></font></div><div><font face="Menlo" class="">public func strideTo(end: Self, stride: Stride) -> StrideThrough<Self></font><br class=""></div><div><font face="Menlo" class="">thing.strideTo(10, stride: 1)</font></div></div></blockquote><div><div><br class=""></div><div>Of the three, only the addObserver are APIs I deem to be acceptable. Of course, there are many examples to prove any given point, but I think these represent the common cases.</div><div><br class=""></div><div>1. Labels are obviously bad (max)</div><div>2. Labels are fine though the external label could be better (addObserver)</div><div>3. Exposes an implementation name that really confuses the API (strideTo)</div><div><br class=""></div><div>(more on this example a bit later)<br class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><blockquote type="cite" class="">For example, the guidelines say to do one thing but the example does<br class="">something different:<br class=""><br class=""><blockquote type="cite" class="">Compensate For Weak Type Information as needed to clarify a parameter’s role.<br class=""><br class="">Especially when a parameter type is NSObject, Any, AnyObject, or a<br class="">fundamental type such Int or String, type information and context at<br class="">the point of use may not fully convey intent. In this example, the<br class="">declaration may be clear, but the use site is vague:<br class=""><br class="">func add(observer: NSObject, for keyPath: String)<br class="">grid.add(self, for: graphics)<br class=""><br class="">To restore clarity, precede each weakly-typed parameter with a noun describing its role:<br class=""><br class="">func addObserver(_ observer: NSObject, forKeyPath path: String)<br class="">grid.addObserver(self, forKeyPath: graphics) // clear<br class=""></blockquote><br class="">This example already had a "for" in the label, but if it were not<br class="">already there, the API, according to the guidelines, should become<br class="">this:<br class=""><br class="">func addObserver(_ observer: NSObject, keyPath path: String)<br class="">grid.addObserver(self, keyPath: graphics) // clear<br class=""></blockquote><br class="">The reason "for" is there is that otherwise you can't tell what the<br class="">relationship between the observer and the keyPath is. For example, if<br class="">it had been "at" instead of "for," it would completely change the<br class="">meaning. "Of" would probably be more descriptive, frankly. But the<br class="">example isn't trying to illustrate anything about that preposition or<br class="">that relationship. <br class=""></div></div></blockquote><div><br class=""></div><div>Right, but the argument is that the API is indeed better with the "for" preposition. I believe it is, I think you are also saying that it is.</div><div><br class=""></div><div>This is the closest guideline that I think attempts to address it:</div><div><br class=""></div><div><div class=""><blockquote type="cite" class="">Clarity at the point of use is your most important goal. Code is read far more than it is written.</blockquote><br class=""></div><div class="">But the clarity here is, ironically, inherently ambiguous. Clarity could mean to make the weak type information known. Clarity could be about intention of how the parameter could be used. Clarity could simply be a more verbose name that provides additional context. I think it would be clear to have guidelines that actually describe what you think make up a good call site.</div><div class=""><br class=""></div><div class=""><span style="font-family: Menlo;" class="">thing.strideTo(10, stride: 1) // clear</span></div><div class=""><span style="font-family: Menlo;" class="">thing.strideTo(10, by: 1) // clear and linguistically better</span></div><div class=""><span style="font-family: Menlo;" class="">thing.strideTo(10, 1) // not clear</span></div></div><div><br class=""></div><div>Both provide some amount clarity at the call site as the value of 1 is quite clear what it means. So in one sense, I agree that the defaults of the language today push you towards clarity.</div><div><br class=""></div><div>To me, the guidelines, as I understand them, lead us to the first option when I believe the intent is to actually get to the second usage.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><blockquote type="cite" class="">Especially when compared with the ObjC import items. Seemingly, the<br class="">ObjC APIs would be using prepositional clauses for parameter labels<br class="">while the Swift labels would simply be more descriptive nouns.<br class=""></blockquote><br class="">I don't know what you mean here, sorry.<br class=""></div></div></blockquote><div><br class=""></div><div>Many of the ObjC APIs will come across with prepositions in the external labels, such as:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">func insert(_ anObject: AnyObject, atIndex index: Int)</font></div></div></blockquote><div><br class=""></div><div>Whereas my interpretation of the Swift 3.0 guidelines would say to design that API like this:</div><div><br class=""></div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">func insert(_ anObject: AnyObject, index: Int)</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div></div></blockquote></div><div>So when we look at the various API options in front of us when designing new APIs, do we use "atIndex", "at", or simply stick with the default "index"? This is where I think the guidelines don't help steer us in any direction.</div><div><br class=""></div><div>However, indeed someone thinks that we should use "at", but based on the guidelines, it's really hard to understand why:</div><div><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><font face="Menlo" class="">- mutating func insert(newElement: Iterator.Element, atIndex i: Int)</font></div><div><font face="Menlo" class="">+ mutating func insert(newElement: Iterator.Element, at i: Int)</font></div></blockquote><div><br class=""></div><div>Again, I agree that "at" reads better at the call site. However, it doesn't provide any real clarity over the default "index" (sidenote: i is still a bad choice ;)), and in some ways, it could be argued that it's slightly ambiguous. Does the below mean insert "12" at the index of "2" or at the value matching "2"?</div><div><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">items.insert(12, at: 2)</font></div></div></blockquote><div class=""><br class=""></div>While this version does not even have that ambiguity. This also relates to the "weak type information" guidelines.<br class=""><div class=""><br class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">items.insert(12, atIndex: 2)</font></div></div></blockquote><div><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><blockquote type="cite" class="">The rules I described are keeping in strict guidance to the API design<br class="">guidelines of adding nouns. So the above would actually be:<br class=""><br class="">func add(observer o: NSObject, keyPath path: String)<br class="">grid.add(observer: self, keyPath: graphics)<br class=""></blockquote><br class="">I'll have to go back and look at the rules you described, but regarding<br class="">the above example, my reason to keep "observer" in the base name is that<br class="">adding observers is really a totally distinct thing from adding, say,<br class="">gesture recognizers, or animation steps, or anything else. There isn't<br class="">one big pot to which you're adding everything. If there were, the<br class="">receiver would be like a collection, and we wouldn't need a noun there<br class="">at all.<br class=""></div></div></blockquote><div><br class=""></div><div>Granted, this is the case some of the times. However, if the protocol is this:</div><div><br class=""></div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">protocol Observable {</font></div><div><font face="Menlo" class=""> func add(observable o: NSObject, forKeyPath path: String)</font></div><div><font face="Menlo" class=""> func remove(observable o: NSObject)</font></div><div><font face="Menlo" class="">}</font></div><div><font face="Menlo" class=""><br class=""></font></div><div><div><br class=""></div></div></div></blockquote></div><div>I actually really hard pressed to come up with a definitive example as to why that should be allowed. The best I can argue is that "add" itself is too generic and could be confused on the implementing type that may also have an "add" function. However, the additional label information helps with that.</div><div><br class=""></div><div>Also, the argument against this one:</div><div><br class=""></div><div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div><div><font face="Menlo" class="">protocol Observable {</font></div><div><font face="Menlo" class=""> func addOb</font><span style="font-family: Menlo;" class="">servable</span><span style="font-family: Menlo;" class="">(o: NSObject, forKeyPath path: String)</span></div><div><font face="Menlo" class=""> func removeO</font><span style="font-family: Menlo;" class="">bservable</span><span style="font-family: Menlo;" class="">(o: NSObject)</span></div><div><font face="Menlo" class="">}</font></div></div></div></blockquote><div></div></div></div><div><br class=""></div><div>Would seem to be me that we are simply duplicating type information. Maybe it's more clear?</div><div><br class=""></div><div>In any respect, I at least submit that "addObservable" in this case is definitely in the grey area.</div><div><br class=""></div><div>However, I absolutely believe that the "strideTo/strideThrough" example is clearly on the side of really being part of the argument label. In both cases we are striding, the difference is on where we stop.</div><div><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div><div><div class=""><font face="Menlo" class="">extension Strideable {</font></div></div></div></div><div class=""><div><div><font face="Menlo" class=""><br class="Apple-interchange-newline"></font></div></div></div><div class=""><div><div><font face="Menlo" class="">- public func stride(to end: Self, by stride: Stride) -> StrideTo<Self></font></div></div></div><div class=""><div><div><font face="Menlo" class="">+ public func strideTo(end: Self, by stride: Stride) -> StrideTo<Self></font></div></div></div><div class=""><div><div><div class=""><font face="Menlo" class=""><br class=""></font></div></div></div></div><div class=""><div><div><div class=""><font face="Menlo" class=""> }</font></div></div></div></div><div class=""><div><div><div class=""><font face="Menlo" class=""><br class=""></font></div></div></div></div><div class=""><div><div><div class=""><font face="Menlo" class=""> extension Strideable {</font></div></div></div></div><div class=""><div><div><font face="Menlo" class=""><br class="Apple-interchange-newline"></font></div></div></div><div class=""><div><div><font face="Menlo" class="">- public func stride(through end: Self, by stride: Stride) -> StrideThrough<Self></font></div></div></div><div class=""><div><div><font face="Menlo" class="">+ public func strideThrough(end: Self, by stride: Stride) -> StrideThrough<Self></font></div></div></div><div class=""><div><div><div class=""><font face="Menlo" class=""><br class=""></font></div></div></div></div><div class=""><div><div><div class=""><font face="Menlo" class=""> }</font></div></div></div></div></blockquote><div class=""><div><br class=""></div><div>This change seems to be simply because the usage of labelled first parameters are frowned up, not because it's actually a better place to describe what is going on.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><blockquote type="cite" class="">However, if the API guidelines are really about creating APIs that are<br class="">to be read in a more English-like manner, like ObjC APIs are designed,<br class="">then the guidelines should really be amended to make that clear.<br class=""></blockquote><br class="">The point of the guidelines is not to make code look like English; it's<br class="">to make code clear and understandable. It happens that in many cases,<br class="">leveraging English grammar serves that purpose well. In other cases<br class="">it's necessary to take a different approach, which is why we have sin(x)<br class="">and zip(x, y). But as I think we make clear, one shouldn't add words<br class="">just to make an API more “English-like.”<br class=""><br class=""><blockquote type="cite" class="">If the intention is truly that Swift APIs are supposed to read as<br class="">naturally as ObjC APIs, <br class=""></blockquote><br class="">Ah... “naturally” is in the eye of the beholder, though.<br class=""></div></div></blockquote><div><br class=""></div><div>Not quite, I think we can objectively say that this:</div><div><br class=""></div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">items.insert(12, atIndex: 2)</font></div></div></blockquote><div></div></div><div><br class=""></div><div>Reads far more naturally than this:</div><div><br class=""></div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">items.insert(12, index: 2)</font></div></div></blockquote><div></div></div><div><br class=""></div><div>In the later, you have to add words to make the API read fluidly. The former simply does by the nature of the words.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><blockquote type="cite" class="">then I completely agree with Joe that there should be a language<br class="">change to actually require the label for parameters.<br class=""><br class="">func addObserver(o: NSObject, path: String) // error: Argument label required for `path`.<br class=""></blockquote><br class="">I'm confused; "path" has an argument label; it's "path."<br class=""></div></div></blockquote><div><br class=""></div><div>What I'm saying is that this is a compiler error:</div><div><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div><div><font face="Menlo" class="">func addObserver(o: NSObject, path: String) // error: Argument label required for `path`.</font></div></div></div></blockquote><div class=""><div><div><br class=""></div><div>While this version is not:</div><div><br class=""></div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">func addObserver(o: NSObject, forKeyPath path: String) // error: Argument label required for `path`.</font></div></div></blockquote><div class=""><div></div></div></div><div><br class=""></div><div>So the external API label is not simply defaulted to the name of the variable within the function scope.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><blockquote type="cite" class="">All of my inclinations for C-style syntactical languages say the API<br class="">should be (in order of my conceptual preference model):<br class=""><br class="">grid.add(observer: self, keyPath: graphics)<br class=""><br class="">// or<br class=""><br class="">grid.addObserver(self, keyPath: graphics)<br class=""><br class="">// or<br class=""><br class="">grid.addObserver(self, graphics)<br class=""></blockquote><br class="">I think we're asking you to let go of your inclinations and think more<br class="">carefully about what will serve the reader of code using your API :-).<br class="">This is less about having a pattern to follow than about how to make<br class="">choices that lead to readable, maintainable code.<br class=""></div></div></blockquote><div><br class=""></div><div>I'm trying to, but we're not really following the ObjC guidelines either. At least on paper. I think you keep talking about readable APIs, but I feel the guidelines keep talking more about descriptive. The difference is subtle, I agree. But I think it's the difference between these two APIs:</div><div><br class=""></div><div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">items.insert(12, atIndex: 2) // or items.insert(12, at: 2)</font></div></div></blockquote><div></div></div><div><br class=""></div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">items.insert(12, index: 2)</font></div></div></blockquote><div></div></div></div><div><br class=""></div><div>Again, it's about which is supposed to be "canonical" Swift.</div><br class=""></div><div>-David</div><br class=""></div></body></html>