<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 class="">I would also like to see a feature that supports concisely wrapping a type akin to Haskell’s newtype. However I wonder if it might be worthwhile to give consideration a more general feature that also supports composition and forwarding more generally, with “newtype” being the simplest, most straightforward use of the feature. </div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 5, 2015, at 9:57 AM, plx <<a href="mailto:plxswift@icloud.com" class="">plxswift@icloud.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I definitely got off on the wrong foot by using `deriving`; what I was trying to ask for is more of a stronger typealias (perhaps `newtype`-esque is the right analogy?), which — at least for my purposes — would *ideally* have the following capabilities / rules:</div><div class=""><br class=""></div><div class="">- when Y is a wrapper around an X, Y has only a single, “synthesized" stored property (of type X)</div><div class="">- the user can control the name of the stored property by one of these mechanisms (which one is used is moot to me):</div><div class=""> - override the name of the synthesized stored property</div><div class=""> - indicate another name and have an accessor auto-generated</div><div class="">- every protocol adopted by X *can* be auto-synthesized for Y </div><div class=""> - but the user has to explicitly request each specific protocol be synthesized…</div><div class=""> - …because it’s very important that it be possible to *not* adopt every one of X’s protocols</div><div class="">- the user can optionally provide some predicate (of type (X) -> Bool), which then:</div><div class=""> - is included as an assert/precondition inside a synthesized `init(_ x: X)` </div><div class=""> - is perhaps/can-be used inside some synthesized `init?(_ x: X)` (this is trickier at present, and might be better as a static func)</div><div class=""> - is ideally available on some methods like `func isInvariantSatisfied() -> Bool; static func isWrappableValue(x: X) -> Bool` (e.g. for debugging/testing)</div><div class=""> - …are essentially for documentation and some very modest runtime verification</div><div class="">- there’s some standard/principled way to do type-erasure "back down to X” as-needed</div><div class=""><br class=""></div><div class="">Only supporting single-value-wrappers should make the needed syntheses essentially trivial as far as I can tell; the only obviously non-trivial aspect is that, in practice, it’d seem likely that you’d want to occasionally “override” the typealiases from X with wrappers thereof; e.g. if you had a type Y wrapping Set<Foo>, you might want Y’s `Index` to be a wrapper around `SetIndex<Foo>` and *not just* `SetIndex<Foo>`; this doesn’t seem overly-complicated semantically but it isn’t “trivial”, either, and would perhaps need additional syntax support to read nicely in-use.</div><div class=""><br class=""></div><div class="">Here are a few concrete example motivating the above requests:</div><div class=""><br class=""></div><div class="">## UI-Level Section/Item Indices</div><div class=""><br class=""></div><div class="">It’s a nice — albeit minor — improvement to work with Int-wrappers like `SectionIndex` and `ItemIndex` rather than as primitive, interchangeable `Int` everywhere. It’s particularly handy if trying to write reasonably-generic implementations of the common UI-level datasource/delegate protocols.</div><div class=""><br class=""></div><div class="">For this:</div><div class=""><br class=""></div><div class="">- it’s nice to have the wrapped value accessible as `index` (as opposed to e.g. `wrappedValue` or `storage`, etc.)</div><div class="">- it’s nice to *not* wind up with the arithmetic operations from `Int`:</div><div class=""> - accidental use of e.g. `*` or `+` or `-` (etc.) on `SectionIndex` or `ItemIndex` is *probably* an error!</div><div class="">- it’s nice to *not* wind up as `IntegerLiteralConvertible`:</div><div class=""> - hard-coded literal indices are rarely advisable in application code!</div><div class=""> - being `IntegerLiteralConvertible` reintroduces transposition-error risk!</div><div class="">- it’s nice to have the constructors assert that the wrapped indices aren’t:</div><div class=""> - == NSNotFound</div><div class=""> - negative </div><div class=""><br class=""></div><div class="">…and although this can be done by hand, it’s an example of a use that *could* be synthesized.</div><div class=""><br class=""></div><div class=""><div class="">## URL Segregation</div></div><div class=""><br class=""></div><div class="">It can be moderately useful to have a bunch of lightweight URL-wrapper types to avoid transposition errors and also to ensure appropriate handling (e.g. using the appropriate URL session); picture, say, `IconImageURL`, `HeroImageURL`, `DetailImageURL`, `APIEndpointURL` (etc.).</div><div class=""><br class=""></div><div class="">If you *did* go this route, some standard way of doing "type-erasure” down to the underlying type can be useful:</div><div class=""><br class=""></div><div class=""> class ActiveTransferMonitor {</div><div class=""> private var activeTransfers: [URL:TransferMetrics] = [:]</div><div class=""><br class=""></div><div class=""> func didBeginTransfer<T:ValueWrapperType where T.WrappedValue: URL>(transferURL: T) {</div><div class=""> self.activeTransfers[transferURL.URL] = TransferMetrics()</div><div class=""> }</div><div class=""> }</div><div class=""><br class=""></div><div class="">…but this is the example I feel least strongly about (it’s just here to motivate the “standard type-erasure mechanism” aspect).</div><div class=""><br class=""></div><div class="">## Bluetooth</div><div class=""><br class=""></div><div class=""><div class="">For Bluetooth LE, you have peripherals, which have *services*, which contain *characteristics*, which can have associated *descriptors*. Each service, characteristic, or descriptor is identified by a unique identifier, which is modeled in CoreBluetooth as instances of the `CBUUID` class.</div></div><div class=""><br class=""></div><div class="">It’s handy here for correctness to have distinct wrapper types, let’s call them `ServiceUUID`, `CharacteristicUUID`, and `DescriptorUUID`, both to guard against simple transposition errors and to make some internal APIs more self-documenting.</div><div class=""><br class=""></div><div class="">It’s handy here for readability to have the wrapped UUID be accessible as, e.g. `.UUID`, and not as some generic `.wrappedValue`:</div><div class=""> </div><div class=""> extension CBPeripheral {</div><div class=""> </div><div class=""> func locatePrimaryService(serviceIdentifier: ServiceUUID) -> CBService? {</div><div class=""> return self.services?.firstElementSatisfying() {</div><div class=""> $0.UUID.isEqual(serviceIdentifier.UUID)</div><div class=""> }</div><div class=""> }</div><div class=""> </div><div class=""> }</div><div class=""><br class=""></div><div class="">At present, the easiest way to get these all setup was as-follows:</div><div class=""><br class=""></div><div class="">- create a protocol like `BluetoothEntityUUIDType` that:</div><div class=""> - also adopts the protocols it should</div><div class=""> - has as many default implementations as possible</div><div class="">- create a struct for `ServiceUUID` that:</div><div class=""> - wraps a single CBUUID instance </div><div class=""> - conforms to `BluetoothEntityUUIDType`</div><div class=""> - manually adds any missing conformances / logic</div><div class="">- create files for `CharacteristicUUID` and `DescriptorUUID`</div><div class=""> - copy-and-paste the definition of `ServiceUUID` into the `CharacteristicUUID` file</div><div class=""> - find-and-replace `Service` with `Characteristic`</div><div class=""> - copy-and-paste the definition of `ServiceUUID` into the `DescriptorUUID` file</div><div class=""><div class=""> - find-and-replace `Service` with `Descriptor`</div></div><div class=""> - edit the `init` (etc.) for `DescriptorUUID ` to add asserts that the passed-in `CBUUID` is one of 6 allowed, pre-defined CBUUIDs applicable to CBDescriptor</div><div class=""><br class=""></div><div class="">…it works, it’s not too terrible as a one-off, but it’s also tedious and runs the risk of implementation drift (especially due to `CBDescriptor` having validation logic the others don’t) in the event that the initial copy-paste-edit cycle needs to be repeated.</div><div class=""><br class=""></div><div class="">Likewise, there’s small things that are nice utilities to tack-onto the various identifier types (utilities to check if they are some well-known ID) that risk getting accidentally blown away if the copy-paste-edit cycle gets repeated; these *can* be defined in other files, but that in turn *can* require “unnatural” choice of visibility (in some cases).</div><div class=""><br class=""></div><div class="">## Closing Comments</div><div class=""><br class=""></div><div class="">For anyone who read this far, thanks for taking the time. I hope the concrete examples helps shed some light on both the motivation and the intended scope for this feature request.</div><div class=""><br class=""></div><div class=""><div class="">The common theme in the examples is that in the individual use, the amount of wrapping is small enough that:</div><div class=""><br class=""></div><div class="">- it can be done by hand</div></div><div class="">- there are not enough wrappers to really justify writing a code-gen tool…</div><div class="">- …especially since (in practice) many of the wrappers benefit from small “customization” here-and-there</div><div class="">- there are readability-and-correctness benefits to having the wrappers available</div><div class=""><br class=""></div><div class="">…but I think having wrapper-synthesis — or a functional equivalent — as an easily-accessible part of the language would open the door more broadly to writing in this style, in ways which aren't always cost-or-time-effective today.</div><div class=""><br class=""></div><div class="">Finally, as I keep mentioning, it’s entirely possible that improvements to the type system will make protocols + default method implementations able to get this features’ benefits without requiring any additional support from the language or tooling; I’d be happy-enough with that outcome also.</div><div class=""><br class=""></div><div class="">Thanks again for the time and feedback. If there’s enough community interest I can prepare a formal proposal, otherwise I’ve said everything I have to say on this idea.</div><div class=""><br class=""></div><div class="">## PS: Product-Type Handling</div><div class=""><br class=""></div><div class="">I honestly think that handling product types with deriving is hard-enough it’s not really worth trying to do; there’s certainly some limited value in being able to synthesize (component-wise) `Equatable` and so on, but once you get past the very foundational protocols like `Equatable` / `Comparable` / `Hashable` / `CustomStringConvertible` / `CustomDebugStringConvertible` you start hitting tricky problems it’s not clear .</div><div class=""><br class=""></div><div class="">EG: how do you synthesize a CollectionType implementation for, e.g., a product of two `CollectionType` types? Sure, you can safely bet the type of the synthesized Element is going to be the product of the component elements, but how do you plan to synthesize the implementation of a proper `ForwardIndexType` from the product of the component collections' `ForwardIndexType`s? There’s a lot of ways to do this, with different resulting iteration ordering and different performance/resource tradeoffs, and it’s hard to do auto-synthesis here that doesn’t either just “pick a winner” (and leave you hanging if you wanted a different implementation) or wind up introducing a mini-language to let you indicate which variant it should synthesize.</div><div class=""><br class=""></div><div class="">Moreover, note that even for, e.g., `Hashable`, there are actually at least a couple common strategies I often see.</div><div class=""><br class=""></div><div class="">One is the `xor`-everything strategy, except:</div><div class=""><br class=""></div><div class="">- it’s IMHO a good idea to rotate some of the constituent hashes to avoid accidentally hashing a lot of stuff to zero</div><div class="">- you don’t always want to hash *everything*</div><div class="">- you may want/need to hash transformed/normalized forms of constituent values, not the “raw” values</div><div class=""><br class=""></div><div class="">Another is the “forward to a good identifier” strategy, e.g.:</div><div class=""><br class=""></div><div class="">- you have a type like `struct ContentMetadata { let identifier: ContentIdentifier; let metadata: [String:MetadataItem] }`</div><div class="">- a good `hashValue` here can be had by simply forwarding the hashValue for `identifier`</div><div class=""><br class=""></div><div class="">…and at least IMHO, in a perfect world, if you *were* to introduce automatic synthesis of `Hashable` for product types, I’d want to be able to indicate which implementation-strategy should be used.</div><div class=""><br class=""></div><div class="">Which, honestly, seems hard to do without baking in special handling for Hashable, and by extension without each synthesis-supporting protocol getting special treatment (and thus leaving “third party” protocols a bit hamstrung in terms of being availble-for-synthesis themselves).</div><div class=""><br class=""></div><div class="">Even mere `Comparable` has similar amounts of fiddly detail — you probably want lexicographic, but in what ordering? do you want any of the constituent types' orderings flipped? — and so on and so forth.</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Dec 5, 2015, at 12:46 AM, Harlan Haskins <<a href="mailto:harlan@harlanhaskins.com" class="">harlan@harlanhaskins.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><pre style="white-space: pre-wrap; background-color: rgb(255, 255, 255);" class=""></pre>I feel like, if we implement automatic derivation for structs that wrap one value, we can just as easily implement automatic derivation for all product types for which the children conform to the protocols in question, and there’s a provided implementation for derivation by combining values.<div class=""><br class=""></div><div class="">Consider Hashable. A very common implementation of <font face="Menlo" class="">hashValue</font> is <font face="Menlo" class="">xor</font>-ing all the members’ hash values together.</div><div class="">We could actually implement this right now given Swift’s reflection system (if we were able to conditionally cast to <font face="Menlo" class="">Hashable</font> or any protocol with a <font face="Menlo" class="">Self</font> requirement).</div><div class=""><br class=""></div><div class="">Consider this:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">struct HashableDerivable deriving Hashable {</font></div><div class=""><font face="Menlo" class=""> let string: String // because String is already Hashable</font></div><div class=""><font face="Menlo" class=""> let integer: Int // and Int is Hashable</font></div><div class=""><font face="Menlo" class=""> // then HashableDerivable is trivially Hashable.</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">/// This implementation is absolutely derivable at compile time.</font></div><div class=""><font face="Menlo" class="">extension HashableDerivable: Hashable {</font></div><div class=""><font face="Menlo" class=""> var hashValue: Int {</font></div><div class=""><font face="Menlo" class=""> return string.hashValue ^ integer.hashValue</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class="">func ==(lhs: HashableDerivable, rhs: HashableDerivable) -> Bool {</font></div><div class=""><font face="Menlo" class=""> return lhs.string == rhs.string && lhs.integer == rhs.integer</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">// one can also use Reflection to derive this at runtime</font></div></div><div class=""><br class=""></div><div class=""><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class="">extension Mirror {</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> func canDeriveHashable() -> Bool {</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> if self.subjectType is Hashable { return true } // this is currently a compiler error</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> for child in self.children {</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> let mirror = Mirror(reflecting: child)</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> if !mirror.canDeriveHashable() { return false }</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> }</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> return true</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> }</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> func deriveHashValue() -> Int {</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> if !self.canDeriveHashable() { fatalError("Boy, I wish this didn't have to happen at runtime.") }</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> guard let firstChild = self.children.first as? Hashable /* also an error */ else { fatalError("no children") }</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> return self.children.dropFirst().reduce(firstChild.hashValue) { (hash, _: (_: String?, value: Any)) -> T in</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> return hash ^ (value as! Hashable).hashValue</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> }</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""> }</font></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class="">}</font></div></div><div style="margin: 0px; line-height: normal;" class=""><font face="Menlo" class=""><br class=""></font></div><div style="margin: 0px; line-height: normal;" class="">Of course, this is something that can be done at compile time, which would make protocol conformance really, really simple.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">We already do this, using the <font face="Menlo" class="">Mirror</font> API, for <font face="Menlo" class="">CustomStringConvertible</font>.</div><div class=""><div class=""><blockquote type="cite" class=""><pre style="white-space: pre-wrap; background-color: rgb(255, 255, 255);" class="">><i class=""> On Dec 4, 2015, at 4:26 PM, John McCall <<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">rjmccall at apple.com</a>> wrote:
</i>><i class="">
</i>>><i class=""> On Dec 4, 2015, at 1:19 PM, plx <<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">plxswift at icloud.com</a>> wrote:
</i>>><i class=""> # A `wrapper` / `deriving` Construct
</i>>><i class="">
</i>>><i class=""> I'm sure a construct along these lines has been requested numerous times and is hopefully already on the roadmap.
</i>>><i class="">
</i>>><i class=""> The point of this email is to put out a reasonably-*concrete* sketch as a way of soliciting community feedback on the specifics of how such a construct might look-and-work within Swift; hopefully I’ve gone far-enough to be interesting, but not too much further than that.
</i>>><i class="">
</i>>><i class=""> ## Design Sketch
</i>>><i class="">
</i>>><i class=""> It ought to be possible to write something like this:
</i>>><i class="">
</i>>><i class=""> // an example:
</i>>><i class=""> struct SectionIndex
</i>>><i class=""> wrapping Int
</i>>><i class=""> as index
</i>>><i class=""> satisfying precondition { $0 >= 0 }
</i>>><i class=""> deriving Equatable, Comparable, Hashable {
</i>>><i class=""> // declaration can continue in here
</i>>><i class=""> }
</i>>><i class="">
</i>>><i class=""> ...which, when compiled, would be "expanded" along these lines:
</i>>><i class="">
</i>>><i class=""> struct SectionIndex {
</i>>><i class="">
</i>>><i class=""> // would have been `wrappedValue` w/out the `as index` clause
</i>>><i class=""> let index: Int
</i>>><i class="">
</i>>><i class=""> init(_ index: Int) {
</i>>><i class=""> precondition(index >= 0)
</i>>><i class=""> // ^ would have been assert(index >= 0)
</i>>><i class=""> // had we used `satisfying { $0 >= 0 }`,
</i>>><i class=""> // and omitted entirely had we omitted a `satisfying` clause
</i>>><i class=""> self.index = index
</i>>><i class=""> }
</i>>><i class="">
</i>>><i class=""> }
</i>>><i class="">
</i>>><i class=""> extension SectionIndex : Equatable {
</i>>><i class=""> }
</i>>><i class="">
</i>>><i class=""> // synthesized unless explicitly written-out
</i>>><i class=""> func ==(lhs: SectionIndex, rhs: SectionIndex) -> Bool {
</i>>><i class=""> return lhs.index == rhs.index
</i>>><i class=""> }
</i>>><i class="">
</i>>><i class=""> // same for Comparable, Hashable, all done in the obvious way
</i>>><i class="">
</i>>><i class=""> // there’s a lot of utility in synthesizing something like this,
</i>>><i class=""> // I can expand on it if necessary:
</i>>><i class=""> extension SectionIndex: ValueWrapperType {
</i>>><i class=""> typealias WrappedType = Int
</i>>><i class=""> }
</i>>><i class="">
</i>>><i class=""> ...where each method/init/subscript/etc in the derived protocols gets synthesized at compile-time, if not explicitly implemented; similarly, if not explicitly-declared, the derived protocols' typealiases can be synthesized in obvious ways, and it seems acceptable to simply fail to compile (and inform the user of the need to make an explicit-declaration) in cases where such synthesis is impossible.
</i>>><i class="">
</i>>><i class=""> I think this enough to sketch the way the feature would look and how it would work.
</i>><i class="">
</i>><i class=""> I’m not sure what work is being done by “wrapping X as Y” here; it seems like just another way of expressing a stored property.
</i>><i class="">
</i>><i class=""> I think we’re all interested in a “deriving” proposal. However, the key problem that a serious proposal would have to address is not picking the syntax, but describing how derivation would actually work. We’d prefer not to just hard-code rules in the compiler for specific protocols.
</i>><i class="">
</i>><i class=""> For example, derivation presumably involves recursively invoking the given operation on each of the stored properties (what does “on” mean? which parameters are changed, and which are passed through?) and then merging the results (how?).
</i>><i class="">
</i>><i class=""> John.
</i>
Apologies for leaving too much out.
I meant to propose that the `deriving` in this place would enforce the wrapper type only wrapped a single stored value, warranting the distinct syntax; I seem to have edited-out both an explicit statement that this assumed a single-stored-property and to have omitted a comment in the `//declaration can continue in here` that no additional stored-properties could be declared (analogous to the rules current applied within extensions).
Yes, constraining a `deriving` construct to only support wrappers containing a single stored property would, on the one hand, be somewhat limiting, but on the other hand it would seemingly allow trivial solutions to the issues you bring up:
- `on` is unambiguous as there’s only one thing it can be “on"
- there’s no ordering-of-operations to have to worry about
- there’s no merging-of-results to have to worry about
- i’m guessing there’s no parameters needing to getting changed (but I’m not 100% on what you mean here)
- there’s no associated-type incoherency to worry about (unless user error introduces it)
…there’s least one tricky case (if you want the wrapper to replace one of the wrapped type’s typealiases with a wrapper).
…and at least for me, there’s enough value in that simplified wrapper-synthesis / deriving-type construct to take the time to check community interest.
Thanks for taking the time to read and send feedback.
PS:
On the other hand, if this becomes writable:
protocol WrapperType {
typealias WrappedValue
var wrappedValue: { get }
}
extension WrapperType : Equatable where WrappedValue: Equatable {
}
func ==<W:WrapperType where W.WrappedValue:Equatable>(lhs: W, rhs: W) -> Bool {
return lhs.wrappedValue == rhs.wrappedValue
}
…etc., then it’s possible (albeit moderately unpleasant) to just write suitable glue logic out longhand on an as-needed basis (and with the caveat that all types wrapping T would potentially adopt all of T’s protocols even when potentially undesirable).</pre></blockquote><div class=""><br class=""></div></div></div></div></div></blockquote></div><br class="">
<img src="https://u2002410.ct.sendgrid.net/wf/open?upn=eLFMrKDT8iBxZ-2Fbnk-2BZqvSchNN-2FvYXdceA0T7VxwkAcH6QSjpcQcd459uJNCcCzeig0LncddaOvmnNr6hXZLUiQV1vJAAX7ugHCoa6UKtkesZOFSSo57bEq53pC5R0qy5VHVzYEsqRjLMXrKHp9pjmRF07ifEgvWrBigQPaWnKSmvNg-2Fi-2BtHPIZACE7T7SyqYBWdlBh1X5bP0rvO-2BhR6c0ITD-2BRcseSqqFrO703nLdA-3D" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-width:0 !important;margin-top:0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-right:0 !important;padding-left:0 !important;" class="">
</div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>