<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><span></span></div><div><div></div><div><br></div><div><br>On 2017. Mar 14., at 2:44, Xiaodi Wu via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr">On Mon, Mar 13, 2017 at 8:30 PM, Tony Allevato via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg">Adding the list back to this reply because I don't believe you meant to reply only to me, and I think it's an important discussion to have :)</div></div><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">On Mon, Mar 13, 2017 at 4:32 PM Vincent Esche &lt;<a href="mailto:regexident.mailinglists@gmail.com" class="m_8773111132439994424gmail_msg" target="_blank">regexident.mailinglists@<wbr>gmail.com</a>&gt; wrote:<br class="m_8773111132439994424gmail_msg"></div></div><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="gmail_quote m_8773111132439994424gmail_msg"><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_8773111132439994424gmail_msg">Automatic generation of Hashable implementation code only "solves" the problem of having to implement `var hashValue`.<div class="m_8773111132439994424gmail_msg">It however only works for some types. By no means for all.</div></div></blockquote><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div></div></div><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="gmail_quote m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg">Certainly, and I never suggested that it would work for every case. I was responding to Sean's point that the compiler should be able to do "good enough" in the common cases and I offered a way that that can be achieved.</div></div></div><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="gmail_quote m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">Take this hypothetical implementation of a HSB color:</div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg">struct Color {</div><div class="m_8773111132439994424gmail_msg"><span class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038gmail-Apple-tab-span m_8773111132439994424gmail_msg" style="white-space:pre-wrap">        </span>let hue: UInt8</div><div class="m_8773111132439994424gmail_msg"><span class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038gmail-Apple-tab-span m_8773111132439994424gmail_msg" style="white-space:pre-wrap">        </span>let saturation: UInt8</div><div class="m_8773111132439994424gmail_msg"><span class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038gmail-Apple-tab-span m_8773111132439994424gmail_msg" style="white-space:pre-wrap">        </span>let brightness: UInt8</div><div class="m_8773111132439994424gmail_msg">}</div></div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">Let the semantic of this type be this:</div><div class="m_8773111132439994424gmail_msg">Any two colors with a `brightness` of `0` are to be considered equal regardless of their respective `hue` or `saturation`. At night all cats are gray.&nbsp;</div></div></blockquote><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">An auto-generated conformance impl for `Color` would most likely be wrong afaict.</div><div class="m_8773111132439994424gmail_msg">And those kind of semantics are everywhere.</div></div></blockquote><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div></div></div><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="gmail_quote m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg">Of course, and in those cases, you wouldn't want to use an auto-derived Equatable or Hashable implementation. Those kinds of semantics are "everywhere" for certain definitions of "everywhere", but similarly, semantics where the hash value of a thing can be determined simply via combination of the hash values of its components are also "everywhere".</div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">I wouldn't suggest that auto-deriving Hashable solves *all* problems, and similarly, your proposal doesn't help in the situation you described either. Your API provides a different way to mix the hue, saturation, and brightness components in an implementation of hashValue, but it doesn't force the user to mix them *correctly* (by excluding hue/saturation if brightness is zero).</div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">So in both cases, users still have to provide custom implementations of == and hashValue. But without auto-deriving, users have to provide them even for the cases where the auto-derived implementation *would have been correct.* &nbsp;Auto-deriving is about reducing the number of types that need to have custom implementations, thereby reducing the chance that a user will do it wrong.</div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">When considering a type with auto-derived Hashable and Equatable, there are two ways it can be wrong:</div><div class="m_8773111132439994424gmail_msg"><br></div><div class="m_8773111132439994424gmail_msg">1) The auto-generated implementations of both == and hashValue don't honor the semantic contract of the type (for example, don't ignore brightness when it's zero).</div><div class="m_8773111132439994424gmail_msg">2) The user overrides the auto-generated implementation of one of ==/hashValue but not both, and violates the contracts between them.</div><div class="m_8773111132439994424gmail_msg"><br></div><div class="m_8773111132439994424gmail_msg">For #1, yes, the compiler generated an incorrect implementation in that case. However, I would argue it's the developer's responsibility to fix it by overriding it if they need different semantics. As I mentioned above, without derivation, the developer could still implement it incorrectly, just as they could with your API.</div><div class="m_8773111132439994424gmail_msg"><br></div><div class="m_8773111132439994424gmail_msg">For #2, this could be solved by requiring users to override both if they override one of them. Now they're back in the same situation as #1—they either did it right, or they did it wrong.</div><div class="m_8773111132439994424gmail_msg"><br></div></div></div><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="gmail_quote m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg">&nbsp;</div><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">Auto-generation clearly is no panacea when it comes to hashing. Especially if it leads to invalid and unsafe default implementations.</div></div></blockquote><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">Auto-deriving cannot produce "unsafe" implementations because it's defined in terms of a function operating over the hash values of its components. It can produce an implementation that does not match the intended semantics of the class that are defined outside of its component values, but that's not the compiler's job to decide; it's up to the user to provide those.</div><div class="m_8773111132439994424gmail_msg"><br></div><div class="m_8773111132439994424gmail_msg">Regarding unsafety, it's worth noting that your ContiguouslyHashable protocol is inherently unsafe and fragile. Imagine that a user implements a struct that they make conform to ContiguouslyHashable because at the time, it's a simple fixed layout type with primitive fields. If they take that type and add a new field to it that isn't contiguously hashable (say, a class reference) and they forget to replace the ContiguouslyHashable conformance, they now have a very broken type, and that behavior isn't caught until *runtime* when things go wrong.</div><div class="m_8773111132439994424gmail_msg"><br></div><div class="m_8773111132439994424gmail_msg">At least with derived conformances, in that situation the *compiler* would see that the type was no longer hashable and emit an error when it's used anywhere that Hashable/hashValue was expected.</div><div class="m_8773111132439994424gmail_msg"><br></div><div class="m_8773111132439994424gmail_msg">So if safety is your motivation, ContiguouslyHashable kind of fights back against that because it gives the user a door they can open—in some cases, accidentally—that produces invalid results.</div><div class="m_8773111132439994424gmail_msg"><br></div><div class="m_8773111132439994424gmail_msg">&nbsp;</div><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">It would however be nice to be able to annotate types&nbsp;for which you want HashVisitable implementations to be generated.</div></div></blockquote><div><br></div><div>That's one of the still-open questions from the last discussion thread on the topic; whether auto-deriving should be automatic for any type where it is possible (as it is now for enums without associated values) or whether the user should have to opt-in.</div><div><br></div><div>&nbsp;</div><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">I actually don't see auto-generation as an alternative to a proper hashing API. But rather as an addition.</div><div class="m_8773111132439994424gmail_msg">HashVisitable and auto-deriving would actually work great together!</div></div></blockquote><div><br></div><div>I completely agree that these ideas complement each other very well! And I also agree that the language would do well to make it easier for users to easily do the right thing. I just feel that *the API proposed here specifically* adds too much complexity for the problem it's trying to solve.</div><div><br></div><div>I'd find it more compelling if it was simplified a bit:</div><div><br></div><div>* The standard library doesn't need to provide a number of hash implementations; it should just provide one that works "well enough" in most cases</div><div>* Hashable doesn't have tie itself to a visitor pattern. It's not necessarily safer because users can still mix the wrong values; in that case, I'd rather the stdlib implementation of the "good enough" hash just be a standalone mixer that the language can encourage users to use.</div></div></div></div></blockquote><div><br></div><div>I agree with this assessment. If SipHash is deemed "good enough," then Swift should offer these as standalone facilities and encourage users to call them in `Hashable`. I think the API design proposed here is much too complex, but offering tried-and-true hash functions is certainly reasonable and would be an improvement over xor.</div></div></div></div></div></blockquote><div><br></div><div>One important point about SipHash and similar secure hash functions is that they work better if all nested components of a hashable value are (recursively) appended to a single hasher, rather than having each component create its own separate hasher instance in its hashValue implementation. Initializing and finalizing the hasher state is not free; it has some nontrivial cost. So ideally only collections would create and finalize hashers; composite types that implement Hashable should not do that.&nbsp;</div><div><br></div><div>Therefore, implementing SipHash as a separate, optional facility for use inside individual hashValue implementations (as opposed to being an outright replacement for it) would be somewhat inefficient. It also wouldn't discourage/prevent people from continuing to use xor and similar ad hoc hashing methods; people would need to discover these useful new hash utilities on their own.</div><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>Certainly also, the documentation for `Hashable` can be improved. In general, however, it's not very convincing to motivate an entire proposal for a new feature based on a documentation bug. Recognize that there are (or at least have been, in past shipped versions of Swift) code snippets in the documentation that _don't even compile_! If we accepted the logic put forward here, we should give up on Swift entirely; after all, if even the official Swift documentation can't provide code that compiles, what hope do the rest of us have?!</div></div></div></div></div></blockquote><div><br></div><div><div><span style="background-color: rgba(255, 255, 255, 0);">IIUC, the proposal suggests that HashVisitable should&nbsp;<i>replace</i>&nbsp;Hashable as the official hashing protocol. This is certainly a major change; but given the sorry state of <i>not just</i> the example given in the Hashable docs, but an <i>alarmingly large fraction of every hand-written hashValue implementation</i> out there (including almost all hashValues I ever made before I gave up &amp; switched to SipHash), perhaps it'd be a good idea to make a clean break here and force people to switch to an API that's a lot easier to get right.</span></div><div><span style="background-color: rgba(255, 255, 255, 0);"><br></span></div><div><span style="background-color: rgba(255, 255, 255, 0);">&lt;rant&gt;</span></div><div><span style="background-color: rgba(255, 255, 255, 0);">Consider that hashValue is pretty much the only place in "everyday" Swift code where people need to routinely use the overflowing arithmetic operators and bitwise operators from the "Advanced Operators" section in the Swift manual. Typical hashValue implementations look like they were written in a different language than the code that surrounds them. They're full of arcane symbols, magical numbers and mystical incantations that are superstitiously repeated over and over, often with no real understanding of their original meaning or function.</span></div><div><span style="background-color: rgba(255, 255, 255, 0);"><br></span></div><div><span style="background-color: rgba(255, 255, 255, 0);">It took a lot of effort to learn C-style for loops (ding!), and they were often tricky to use correctly; but it was certainly possible to learn them well enough to write decent code. In contrast, practically nobody I know is able to write a&nbsp;<i>good</i>&nbsp;hashValue implementation from scratch for even simple structs like CGPoint with&nbsp;<i>any</i>&nbsp;confidence. Not just junior programmers: nobody. One has to be some sort of wizard to do it. The hashValue API is a miserable failure.</span></div></div><div><span style="background-color: rgba(255, 255, 255, 0);">&lt;/rant&gt;</span></div><div><span style="background-color: rgba(255, 255, 255, 0);"><br></span></div><div>Automatic generation of hashValue implementations using SipHash would (mostly) resolve the usability issue, but not the efficiency thing. Perhaps it'd be acceptable to simultaneously implement autogeneration and to switch over to (simplified!) visitor-based hashing in the same compiler release—so that the migrator's fixits would simply suggest removing hashValue implementations instead of replacing them with something that looks dramatically different.&nbsp;</div><div><br></div><div>If the boilerplate generator would include some sort of syntax to explicitly add/remove specific properties from/to the scope of hashing &amp; equality, then only people implementing hashed collections would ever need to care about the specific hashing APIs, leaving other programmers blissfully and safely unaware of such esoteric concerns.</div><div><br></div><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>&nbsp;</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="gmail_quote m_8773111132439994424gmail_msg"><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_8773111132439994424gmail_msg"><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">In fact they <a href="https://is.gd/iy5770" class="m_8773111132439994424gmail_msg" target="_blank">already do in other languages</a>.</div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div></div><div><div class="h5"><div class="gmail_extra m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"><div class="gmail_quote m_8773111132439994424gmail_msg">On Mon, Mar 13, 2017 at 8:51 PM, Tony Allevato via swift-evolution <span dir="ltr" class="m_8773111132439994424gmail_msg">&lt;<a href="mailto:swift-evolution@swift.org" class="m_8773111132439994424gmail_msg" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br class="m_8773111132439994424gmail_msg"><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_8773111132439994424gmail_msg">I'm not convinced this is the right approach: it couples the fact that a type is hashable with a specific strategy for implementing the hash value computation.&nbsp;<div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">Instead, the language should make efforts to avoid requiring the user to think about hashing algorithms *at all*; to answer Sean's question a couple messages up, I've <a href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad" class="m_8773111132439994424gmail_msg" target="_blank">proposed in the past</a>&nbsp;(rough working draft) adding derivation of Equatable and Hashable for structs and enums where it's possible to automatically do so (for example, if all of the enum's associated values are Equatable/Hashable). I've been experimenting with an implementation in the compiler and I have something that works for enums, except for recursive ones. I haven't started structs yet because I think there are more open questions there, and I hope to propose enums and structs independently so that the enum one doesn't get bogged down by the struct one.</div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">The core team seems to be aware of the need for this; the logic that derives Equatable/Hashable for enums without associated values also has TODO comments to handle those with associated values, and to handle structs as well. Slava Pestov mentioned a while back that they encouraged PRs on it, which is why I started, but my free time has been limited lately.</div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div><div class="m_8773111132439994424gmail_msg">That being said, I *do* think there would be value in having some kind of hash "mixer" as part of the standard library and strongly encouraging through documentation that hashValue implementors use it. Getting the function right is the hard part, and if Swift both (1) took care of it for you by default in many cases and (2) made the harder cases easier by providing a high quality canned implementation, I think we'd have a much cleaner solution than what is being proposed here.</div><div class="m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"></div></div><div class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038HOEnZb m_8773111132439994424gmail_msg"><div class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038h5 m_8773111132439994424gmail_msg"><br class="m_8773111132439994424gmail_msg"><div class="gmail_quote m_8773111132439994424gmail_msg"><div dir="ltr" class="m_8773111132439994424gmail_msg">On Mon, Mar 13, 2017 at 12:18 PM Sean Heber via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="m_8773111132439994424gmail_msg" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br class="m_8773111132439994424gmail_msg"></div><blockquote class="gmail_quote m_8773111132439994424gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Is there any reason the API couldn’t be expressed as something along these lines?<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
func hash() -&gt; [Hashable] {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&nbsp; return [x, y]<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
l8r<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
Sean<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt; On Mar 13, 2017, at 2:15 PM, David Hart &lt;<a href="mailto:david@hartbit.com" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">david@hartbit.com</a>&gt; wrote:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; On 13 Mar 2017, at 18:54, Sean Heber via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; I’m dumb when it comes to proper hashing, but it’s such a tediously common thing in my experience to need to add Hashable to some kind of a struct so I can stash it in a set or use it as a dictionary key. Is there really no way to make this all more automatic? I have to be honest - this proposal seems *harder* to understand than the way it works now.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt; It's not really harder: just call hash on each of your type's significant values:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt; x.hash(&amp;hasher)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt; y.hash(&amp;hasher)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt; How would you implement hashValue in a simpler way, remembering that 'x ^ y' is an incorrect implementation?<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; Of course the easiest would be if the language could just do this “good enough" for me using reflection or whatever and if I really did run into a problem where I wanted to do this myself, I could override something.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; Perfect is the enemy of good.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; l8r<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; Sean<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; On Mar 13, 2017, at 10:38 AM, Vincent Esche via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Hi there,<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; I've written up a proposal for an overhaul/replacement of the Hashable protocol and would love to hear your feedback on it!<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Rendered | Blog Post<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Cheers,<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Vincent<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Ps: I'd like to thank David Hart (@hartbit) for his great editorial feedback on this proposal. 👍<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; HashVisitable<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;• Proposal: SE-NNNN<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;• Authors: Vincent Esche<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;• Review Manager: TBD<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;• Status: Awaiting review<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Introduction<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Replace the Hashable protocol by two new procotols (Hasher and HashVisitable) to improve safety, versatility and learnability.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Motivation<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Implementing Hashable is difficult and the consequences if not done well have dire performance and safety repercussions.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; The documentation of Hashable lists a sample implementation of var hashValue:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; /// A point in an x-y coordinate system.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; struct GridPoint {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;var x: Int<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;var y: Int<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension GridPoint: Hashable {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;var hashValue: Int {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp; &nbsp; &nbsp;return x.hashValue ^ y.hashValue<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;static func == (lhs: GridPoint, rhs: GridPoint) -&gt; Bool {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp; &nbsp; &nbsp;return lhs.x == rhs.x &amp;&amp; lhs.y == rhs.y<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Calculating the hashes of all GridPoints (given the above implementation) on a 1000 × 1000 grid …<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; let (width, height) = (1000, 1000)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; let total = width * height<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; var hashes = Set&lt;Int&gt;()<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; for x in 0..&lt;width {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;for y in 0..&lt;height {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp; &nbsp; &nbsp;hashes.insert(GridPoint(x: x, y: y).hashValue)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; print("\(hashes.count) unique hashes out of a total of \(total).")<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; … results in just 1024 unique hash values for 1_000_000 unique values.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; In other words: The recommended implementation causes 99.9% of values to trigger a hash collision.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Out of those 1_000_000 values the median collision count was 976 with min and max being 976 and 1000respectively.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; The collision rate will have negative impact in algorithms which heavily use hashValue like the ones in Dictionaryand Set. Furthermore, it increases the vulnerability to DDOS attacks when exposed to the web.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; If even the official Swift documentation gets the implementation of hashValue wrong, then who is to expect the average Swift programmer to do any better?<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; In contrast, running the same snippet using HashVisitable and the semi-secure Fnv1aHash (see below) results in zero collisions!<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Finally, the design of the Hashable protocol forces the use of one implementation without the possibility of switching between multiple hashing algorithms.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Proposed solution<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Instead of coupling the hashing algorithm with each and every Swift type, we should provide a hashing API based on the visitor-pattern. By freeing application developers from the burden of having to implement hashing algorithms, the Standard Library can provide default ones which fulfill collision, performance and security goals. Furthermore, it would allow developers to swap to different algorithms based on the use case.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Detailed design<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; The proposal deprecates the Hashable protocol and introduces the following two:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; protocol Hasher<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; mutating func finish() -&gt; Int<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; mutating func write(bytes<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; : UnsafeRawBufferPointer)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; protocol HashVisitable<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; func hash&lt;H: Hasher&gt;(_ hasher: inout<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; H)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Hasher is the protocol which represents a hashing algorithm, and HashVisitable replaces Hashable. For types entirely represented by their memory layout, the following protocol would provide a default implementation:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; protocol ContiguouslyHashable: HashVisitable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension ContiguouslyHashable {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;func hash&lt;H: Hasher&gt;(_ hasher: inout H) {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp; &nbsp; &nbsp;var mutableSelf = self<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp; &nbsp; &nbsp;try! Swift.withUnsafeBytes(of: &amp;mutableSelf) {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hasher.write(bytes: $0)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp; &nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension Bool : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension UInt8 : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension UInt16 : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension UInt32 : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension UInt64 : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension UInt : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension Int8 : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension Int16 : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension Int32 : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension Int64 : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension Int : ContiguouslyHashable {}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; The Standard-Library would then provide a set of hashing implementations specific to each purpose. A possible choice for hashing algorithms would be the reasonably fast SipHash-2-4, and the reasonably secure SipHash-4-8.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; FNV-1A is another popular semi-secure but blazingly fast hash algorithm, which – for the sake of demonstration – could be implemented as follows:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; struct Fnv1aHash<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; fileprivate var state: UInt<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; init(seed: UInt<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; ) {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; self.state = seed &amp;+ 14695981039346656037<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension Fnv1aHash: Hasher<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; mutating func write(bytes<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; : UnsafeRawBufferPointer) {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; for byte in<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; bytes {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; self.state = (self.state ^ UInt(byte)) &amp;* 1099511628211<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp; &nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; mutating func finish() -&gt; Int<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; return unsafeBitCast(self.state, to: Int.self<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; )<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Coming back to the sample code present in the Hashable documentation, the new implementation would look like:<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension GridPoint: HashVisitable<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; func hash&lt;H: Hasher&gt;(_ hasher: inout<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; H) {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; self.x.hash(&amp;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; hasher)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; self.y.hash(&amp;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; hasher)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Source compatibility<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Making use of "extending protocols to conform to protocols":<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; extension Hashable: HashVisitable<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; func hash&lt;H: Hasher&gt;(_ hasher: inout<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; H) {<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; self.hashValue.hash(&amp;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; hasher)<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;&nbsp; &nbsp;}<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; }<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Effect on ABI stability<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; n/a<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Effect on API resilience<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; This feature should be possible to add/remove without breaking ABI.<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; Alternatives considered<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; n/a<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; ______________________________<wbr>_________________<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; swift-evolution mailing list<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; <a href="mailto:swift-evolution@swift.org" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;&gt; <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt;<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; ______________________________<wbr>_________________<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; swift-evolution mailing list<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; <a href="mailto:swift-evolution@swift.org" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
&gt;&gt; <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
______________________________<wbr>_________________<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
swift-evolution mailing list<br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br class="m_8773111132439994424m_1052664451246294635m_-2288818070518422038m_858664506594008476gmail_msg m_8773111132439994424gmail_msg">
</blockquote></div>
</div></div><br class="m_8773111132439994424gmail_msg">______________________________<wbr>_________________<br class="m_8773111132439994424gmail_msg">
swift-evolution mailing list<br class="m_8773111132439994424gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="m_8773111132439994424gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="m_8773111132439994424gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="m_8773111132439994424gmail_msg" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br class="m_8773111132439994424gmail_msg">
<br class="m_8773111132439994424gmail_msg"></blockquote></div><br class="m_8773111132439994424gmail_msg"></div>
</div></div></blockquote></div></div></div>
<br>______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
<br></blockquote></div><br></div></div>
</div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-evolution mailing list</span><br><span><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></div></body></html>