<html><head><style>
body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        padding:1em;
        margin:auto;
        background:#fefefe;
}
h1, h2, h3, h4, h5, h6 {
        font-weight: bold;
}
h1 {
        color: #000000;
        font-size: 28pt;
}
h2 {
        border-bottom: 1px solid #CCCCCC;
        color: #000000;
        font-size: 24px;
}
h3 {
        font-size: 18px;
}
h4 {
        font-size: 16px;
}
h5 {
        font-size: 14px;
}
h6 {
        color: #777777;
        background-color: inherit;
        font-size: 14px;
}
hr {
        height: 0.2em;
        border: 0;
        color: #CCCCCC;
        background-color: #CCCCCC;
display: inherit;
}
p, blockquote, ul, ol, dl, li, table, pre {
        margin: 15px 0;
}
a, a:visited {
        color: #4183C4;
        background-color: inherit;
        text-decoration: none;
}
#message {
        border-radius: 6px;
        border: 1px solid #ccc;
        display:block;
        width:100%;
        height:60px;
        margin:6px 0px;
}
button, #ws {
        font-size: 12 pt;
        padding: 4px 6px;
        border-radius: 5px;
        border: 1px solid #bbb;
        background-color: #eee;
}
code, pre, #ws, #message {
        font-family: Monaco;
        font-size: 10pt;
        border-radius: 3px;
        background-color: #F8F8F8;
        color: inherit;
}
code {
        border: 1px solid #EAEAEA;
        margin: 0 2px;
        padding: 0 5px;
}
pre {
        border: 1px solid #CCCCCC;
        overflow: auto;
        padding: 4px 8px;
}
pre > code {
        border: 0;
        margin: 0;
        padding: 0;
}
#ws { background-color: #f8f8f8; }
.bloop_markdown table {
border-collapse: collapse;
font-family: Helvetica, arial, freesans, clean, sans-serif;
color: rgb(51, 51, 51);
font-size: 15px; line-height: 25px;
padding: 0; }
.bloop_markdown table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
.bloop_markdown table tr:nth-child(2n) {
background-color: #f8f8f8; }
.bloop_markdown table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr th :first-child, table tr td :first-child {
margin-top: 0; }
.bloop_markdown table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
.bloop_markdown blockquote{
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
code, pre, #ws, #message {
word-break: normal;
word-wrap: normal;
}
hr {
display: inherit;
}
.bloop_markdown :first-child {
-webkit-margin-before: 0;
}
code, pre, #ws, #message {
font-family: Menlo, Consolas, Liberation Mono, Courier, monospace;
}
.send { color:#77bb77; }
.server { color:#7799bb; }
.error { color:#AA0000; }</style></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="bloop_markdown"><p>Hello folks,</p>
<p>I’d like to revive the discussion about the <a href="https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#variadic-generics"><strong>Variadic generics</strong></a> feature from the generics manifesto.</p>
<p>There exist an older draft proposal from <a href="https://github.com/austinzheng/swift-evolution/blob/az-variadic-generics/proposals/XXXX-variadic-generics.md">Douglas Gregor and Austin Zheng</a>.</p>
<p>As part of this discussion I also would like to talk about the possibly of a new enum type <code>Wrapped</code> (some of you might be familiar with <code>Result</code> or <code>Either</code> type). To be clear about this, I do not want to introduce a <em>union type</em> here, because if you might not know:</p>
<blockquote>
<p><a href="https://lists.swift.org/pipermail/swift-evolution-announce/2016-June/000182.html">Disjunctions (logical ORs) in type constraints:</a> These include anonymous union-like types (e.g. (Int | String) for a type that can be inhabited by either an integer or a string). “[This type of constraint is] something that the type system cannot and should not support.”</p>
<p>Source: <a href="https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md#miscellaneous">Commonly Rejected Changes</a></p>
</blockquote>
<p>But I still have hope for the infix <code>|</code> type operator as part of the <code>Wrapped</code> enum.</p>
<p>To beginn with, I’d like to thank to Douglas and Austin for their work back then and putting this draft together. To be honest while reading the proposal I found it hard to keep track of where the prefix <code>…</code> and where the postfix <code>…</code> was used. Especially it was really confusing to understand the behavior of each <code>…</code> operator.</p>
<p>Let’s look at the following 3 examples from the proposal:</p>
<pre><code class="swift">struct Foo<...C : Collection> {
// Indices and C are bound to be the same length.
typealias ...Indices = C.Index...
// A value vector of indices
var (...startIndices): (Indices...)
init(...x: C...) {
startIndices... = x.startIndex...
}
}
struct Foo<...T : CustomStringConvertible> {
var (...descriptions): (String...)
init(...x: T) {
// .description goes from Tn -> String
// Because of this, descriptions' length is identical to that of T.
descriptions... = x.description...
}
}
// NOT ALLOWED!!!
struct Foo<...T : CustomStringConvertible> {
var (...descriptions): (String...)
mutating func doSomething() {
descriptions... = ("foo", "bar", "baz")
}
}
</code></pre>
<p>The first problem I realize here, is that the <code>...</code> prefix has no ability to describe its own boundary and therefore the last example is not possible.</p>
<p>As contrast to this I’d like to pitch a new keyword <code>vector</code> and <code>vector(Boundary_Size)</code> (we could also use <code>params</code> instead, like in C#). Without the explicit <code>Boundary_Size</code>, which could be from 1 to (positive) n, the vector is unbound and acts exactly like the proposed <code>...</code> prefix.</p>
<p>Let’s rewrite and reposition a few things from above with the new keyword:</p>
<pre><code class="swift">struct Foo<vector C : Collection> {
// Indices vector is bound to be the same length as its parent scope C vector, because we're using its `Index` here.
typealias vector Indices = vector C.Index
// A value vector of indices
// Note: We *might* omit `vector` here for the value, because its type
// already is a vector, or we want to be explicit everywhere?!
vector var startIndices: Indices
// Alternative 1 (preferred):
var startIndices: Indices
// Alternative 2 (still okay):
var startIndices: vector Indices
// Alternative 3 (really strange):
vector var startIndices: vector Indices
// Same here, `C` is a vector, so we could omit `vector` keyword before x
init(vector x: C) {
// Since the vectors `startIndices` and `x` are bound by a
// unbound *parent scope vector* we don't need the postfix `...`
self.startIndices = x.startIndex
}
// Alternative 1:
init(x: C) {
self.startIndices = x.startIndex
}
// Alternative 2:
init(x: vector C) {
self.startIndices = x.startIndex
}
}
struct Foo<vector T : CustomStringConvertible> {
// When there is no other context than the unbound parent scope vector,
// the following vector will have the same length, otherwise it will be unbound.
var descriptions: vector String
init(x: T) {
// .description goes from Tn -> String
// Because of this, descriptions' length is identical to that of T.
self.descriptions = x.description
}
}
// Allowed now
struct Foo<vector T : CustomStringConvertible> {
// This vector has an explicit boundary size and therefore not bound
// to vector T
vector(3) var descriptions: String
// Alternative:
var descriptions: vector(3) String
mutating func doSomething() {
// Assigning can be made with tuples
self.descriptions = ("foo", "bar", "baz")
}
}
</code></pre>
<p>From my personal point of view this new approach is way easier to read. A really good thing about it, is that it eliminates the ugly pre-/postfix <code>...</code> confusion.</p>
<hr>
<p>Now let’s scratch the surface of the mentioned <code>Wrapped</code> enum.</p>
<p>Recently I bumped into an issue where no Swift feature could nicely solve it for me, not even conditional conformances with it’s full power. The only possible solution would be such a <code>Wrapped</code> enum (the only one in the whole language) or the ability to implicitly wrap any instances into enum cases when it’s possible.</p>
<pre><code class="swift">// Implicitly wrapping
enum MyEnum {
case string(String)
case integer(Int)
}
let int = 42
// Matched against the cases and wrapped if possible, otherwise it'll be an error
let e1: MyEnum = int
// There is no `ExpressibleByStringLiteral` here, so the literal fallback to
// its default type `String`, than matched against all the cases and wraps into `.string(String)`
let e2: MyEnum = "Swift"
// Wrapped enum, with the same functionality as above.
enum Wrapped<vector T> {
// How about the ability of extracting the vector index?
vector case vector.index(T)
// Alternative
vector case #(T)
}
let e3: Wrapped<String, Int> = 0 // implicitly wrapped into `.1(Int)`
switch e3 {
case .0(let stringValue):
print(stringValue)
case .1(let intValue)
print(intValue)
}
// Yes, this is not a typo but a possible useless artifact.
// For the Wrapped enum we could check for same types (probably very complex to achieve), or just leave it as is.
let e4: Wrapped<String, String> = "test"
switch e3 {
case .0(let stringValue):
print(stringValue)
case .1(let stringValue)
// Will never print
print(stringValue)
}
</code></pre>
<p>As mentioned above I’d like to use the infix <code>|</code> type operator for the <code>Wrapped</code> enum as a shortcut.</p>
<pre><code class="swift">let x: Wrapped<A, B, C> = ...
let x: A | B | C = ...
// x.0(A)
// x.1(B)
// x.2(C)
</code></pre>
<hr>
<p>Any feedback is much appreciated. :)</p>
<p></p></div><div class="bloop_original_html"><style>body{font-family:Helvetica,Arial;font-size:13px}</style><div id="bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px; color: rgba(0,0,0,1.0); margin: 0px; line-height: auto;"><br></div><br><div id="bloop_sign_1479801817699141120" class="bloop_sign"><div style="font-family:helvetica,arial;font-size:13px">-- <br>Adrian Zubarev<br>Sent with Airmail</div></div></div><div class="bloop_markdown"><p></p></div></body></html>