<div dir="ltr">A Scala like new-Iterator pattern, using path-dependent typing, might be:<div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>struct Range<T: Comparable> { ... }</div><div>func ..< <T: Comparable>(lowest: T, highest: T) { ... }</div><div><br></div><div>struct Array<T>: Collection {</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>static struct Iterator { ... } // Note static</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>...</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>func next(iterator: inout Iterator) -> Element? { ... }</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>subscript(range: Range<Int>) -> [E] { ... }</div></blockquote></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>}</div></blockquote><div><br></div><div>With new iterators, Scala style, the following is legal:</div><div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>let a = [Int]()</div><div><font size="2"><span style="background-color:rgba(255,255,255,0)">let b = [Int]()</span></font></div><div><font size="2"><span style="background-color:rgba(255,255,255,0)">let i = a.Iterator() // Create an instance of an inner type, type associated with an instance of its outer type</span></font></div><div><font size="2">let aE = a.next(&i)</font></div><div><font size="2">let r = 1 ..< 2</font></div><div><font size="2">let aS = a[r]</font></div><div><font size="2">let bS = b[r] // OK since `r` is not associated with `a` because `Range` is not nested within `Array`</font></div></blockquote><div><font size="2"><br></font></div><div><font size="2">but not</font></div><div><font size="2"><br></font></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><font size="2">let bE = b.next(&i) // Type error because `i` is associated with `a` not `b`</font></div></blockquote><div><font size="2"><span style="background-color:rgba(255,255,255,0)"><br></span></font></div><div><font size="2"><span>The type `Iterator` is static because it does not capture the enclosing type instance, the enclosing type instance, `a` in the example, is solely used for typing. Non-static inner types capture an instance of their outer type.</span></font></div><div><font size="2"><span><br></span></font></div><div><font size="2"><span>The other interesting pattern using inner types is old-style iterators, conventional external iterators:</span></font></div><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><br></div><div>struct Array<T>: Collection {</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px">struct Iterator { ... } // Note *not* static, therefore captures outer instance when created</blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px">...</blockquote></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px">}<br></blockquote><div><br></div><div><div>With external iterators, Scala style, the following is legal:</div><div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>let a = [Int]()</div><div><span style="background-color:rgba(255,255,255,0)">let i = a.Iterator() // Create an instance of an inner type, *capturing* and type associating with an instance of its outer type</span><br></div><div><font size="2">let aE = i.next()</font></div><div><br></div></blockquote></div>Whilst this pattern in use is very similar to what Swift currently does it is a lot easier to optimise because an escape analysis can tell if the capture of `a` by `i` needs to increment the reference counting or not. The compiler knows that `i` has captured `a` which allows this optimisation. I *think* that Java's JVM's escape analysis does this optimisation.</div><div><br></div><div>Assuming that Swift could optimise inner types then this would allow retention of traditional external iterators.</div><div><br>On Monday, 18 April 2016, Dmitri Gribenko via swift-evolution <<a>swift-evolution@swift.org</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">On Sun, Apr 17, 2016 at 11:14 PM, Thorsten Seitz <<a>tseitz42@icloud.com</a>> wrote:<br>
> Preventing indices of one collection being used by another collection can be done by using path dependent types like in Scala.<br>
><br>
> Then 'i' would have type a.Index (where 'a' is the instance!) and therefore b[i] would not typecheck as it would require an index of type b.Index<br>
<br>
This is an interesting concept! Would this work with slices? You<br>
should be able to use indices from slices with the base collection,<br>
and vice-versa (when indices are in range).<br>
<br>
Dmitri<br>
<br>
--<br>
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if<br>
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <<a>gribozavr@gmail.com</a>>*/<br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a>swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div>
</div>