<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Fri, Mar 10, 2017 at 6:18 AM Haravikk via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="gmail_msg">So the topic of global functions like min/max came up on the thread about adding a standard clamp method, and it got me to thinking whether there was a better way to define most global methods.<div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Currently for example there are two global functions min and max; very useful, and don&#39;t make much sense as instance methods, but they&#39;re not as easily discoverable as a static method declared under relevant type(s). We could get around this by defining such functions both as a static method, and as a global function, but it means duplicate code and by convention only.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">An alternative is to remove the need for duplicate methods using a new global keyword for a method declaration, telling Swift to define it as both a static method <b class="gmail_msg">and</b> a global function. This allows the function to be grouped logically under a type, making it a bit neater, but without losing the benefit of the global definition. For example:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>protocol Comparable {</font></div><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">                </span>global func min(_ a:Self, _ b:Self) -&gt; Self { return a &lt; b ? a : b }</font></div><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">                </span>global func max(_ a:Self, _ b:Self) -&gt; Self { return a &gt; b ? a : b }</font><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>}</font></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">With this single definition both of the following are now valid:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let min = Int.min(1, 3)</font></div><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let max = max(5, 10)</font></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">In the second case, Swift looks at all global definitions for &quot;max&quot; in order to locate the best match, leading it to Int.max.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">It&#39;s a relatively small change, but helps with neatness. It may also be good for consistency if we ever get the ability to define operators within types (though I&#39;m not sure where we are with that?), as they could potentially just use the same format like-so:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>struct MyType : Equatable {</font></div><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">                </span>global func == (_ a:MyType, _ b:MyType) -&gt; Bool { /* Determine equality */ }</font></div><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>}</font></div></div></blockquote><div><br></div><div>&quot;If we ever...&quot;? SE-0091 allowed this (using static instead of global) and it&#39;s implemented in Swift 3. Or are you asking about something different?</div><div><br></div><div>Your idea is related to that proposal (in the sense that it&#39;s the inverse, kind of). So I would imagine that some of the compiler machinery to do something similar here is (or was) already there or close to it. But the type checker has already been augmented to look up static members specifically for operators already, at least.<div><br></div><div>I&#39;ve definitely felt the need for something like this recently—in writing some generic code constrained by FloatingPoint, I wanted to be able to use the trig functions as well. Since they aren&#39;t part of that protocol, I created a new one named ExtendedFloatingPoint and added methods for them, and then global trampolines that called them:</div><div><br></div><div>```</div><div>public protocol ExtendedFloatingPoint: FloatingPoint {</div><div>  static func cos(_ v: Self) -&gt; Self</div><div>}</div><div>extension Float: ExtendedFloatingPoint {</div><div>  static func cos(_ v: Float) -&gt; Float { return cosf(v) }</div><div>}</div><div>public func cos&lt;T: ExtendedFloatingPoint&gt;(_ v: T) -&gt; T { return T.cos(v) }</div><div>```</div><div><br></div><div>It works, but I have two problems with this approach:</div><div><br></div><div>(1) I don&#39;t want two ways to call the same thing; the static method inside the protocol is *purely* an implementation detail and I&#39;d prefer it if it was hideable so that only the global trampoline can call it. I don&#39;t want anyone externally to ever write &quot;Double.cos(someDouble)&quot;, because it&#39;s redundant, but since it&#39;s a protocol requirement and needs to be overridden, it must be at least as accessible as the type conforming to it.</div><div><br></div><div>(2) The trampoline is annoying boilerplate anyway (my original version of SE-0091 relied on trampolines and Doug Gregor assisted with the rewrite that made the lookup for statics &quot;just work&quot;).<br><br>I&#39;m going to offer a different take: solving (1) could be done if I had a way to express a hidden requirement that other types can *implement* but not *call*. It&#39;s kind of a weird idea, but it&#39;s something I&#39;ve had come up in my designs a few times when I&#39;ve tried using protocols to separate internal and public parts of various APIs. And idea like this might get tricky when you start talking about types outside the module boundary that defines the protocol, though. If Foo.T conforms to Bar.U and Bar.U has such a requirement (say, func v())...</div><div><br></div><div>* Can anything in Foo call T.v() directly?</div><div>* Can anything in Foo.T itself call it, or does it also have to go through the trampoline even on itself?</div><div>* What if Bar.U is a retroactive conformance on Foo.T via an extension? Does/how does that affect the visibility of v()?<br><br>My C# is rusty but I believe its explicit interface implementation feature is kind of like this—I don&#39;t know the details, though. I think the hiding is decided entirely by the implementor, not by the interface, so it&#39;s not quite the same.</div><div><br></div><div>An approach like this, of course, has the downside that it leaves the trampoline boilerplate around.</div><div><br></div><div>That being said, I&#39;ll play devil&#39;s advocate a bit: just how much demand is there for a feature that would only work specifically for globals? Are there a lot of other use cases outside mathematic/numeric libraries to motivate it? It seems fairly narrowly scoped (whereas the ability to hide protocol implementations would be more flexible at the cost of slightly more code).</div><div><br><div class="gmail_quote"><br class="inbox-inbox-Apple-interchange-newline"></div></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"> </div></div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg">I just think it&#39;s a neater way to do this than currently requiring separate declarations for the static and global versions, especially since one usually just calls the other anyway, anyone have any thoughts?</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">I normally argue against new keywords, but in this case it may be justified, as I considered an attribute but it would only end up requiring static anyway, so it seemed neater to just have a new category &quot;above&quot; static that is both static and global, since a global non-static doesn&#39;t make any sense. However, one advantage of a @global attribute is that it could potentially take a different name for the global function, so I could (but probably wouldn&#39;t) define something like:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><font face="Monaco" class="gmail_msg"><span class="m_4003402677772258881Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>@global(&quot;min&quot;) static func smallerOfTwo(_ a:Self, _ b:Self) -&gt; Self { return a &lt; b ? a : b }</font></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">So here, although the method name is smallerOfTwo, it is exposed globally as &quot;min&quot;. Though I don&#39;t know much need there would be for something like that.</div></div>_______________________________________________<br class="gmail_msg">
swift-evolution mailing list<br class="gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution<br></a><br class="gmail_msg">
</blockquote></div></div>