<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 11, 2015, at 8:01 AM, Marc Knaup &lt;<a href="mailto:marc@knaup.koeln" class="">marc@knaup.koeln</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Thank you for your thorough answer.<div class=""><br class=""></div><div class="">So when direct and indirect cases already look the same for the type system then why is there the <font face="monospace, monospace" class="">indirect</font> modifier in the first place?</div><div class="">Couldn't the compiler just automatically box variables which would cause a recursion? For structs, enums and probably tuples.</div></div></div></blockquote><div><br class=""></div>The compiler could certainly infer ‘indirect’ if there is a cycle of unsubstituted types, eg,</div><div><br class=""></div><div>enum A {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>case X</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>case Y(S) // could infer indirect here</div><div>}</div><div><br class=""></div><div>struct S {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>let a: A</div><div>}</div><div><br class=""></div><div>However, the circularity might be introduced by a generic type substitution:</div><div><br class=""></div><div><div>enum A&lt;T, U&gt; {</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>case X</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>case Y(T)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>case Z(U)</div><div>}</div><div><br class=""></div><div>struct R {}</div><div><br class=""></div><div>struct S {</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>let a: A&lt;S, R&gt;</div><div>}</div><div><br class=""></div><div>Here, A&lt;S, R&gt; needs Y to be indirect, but A&lt;R, S&gt; needs Z to be indirect. This would put the indirectness on different cases for different substitutions of the same generic type, which would complicate code generation for functions which manipulate A&lt;T, U&gt; generically.</div><div><br class=""></div><div>Also even if ‘indirect’ could always be inferred, it seems like a good idea to give the user control over where the indirection occurs — this can have an effect on the size of the enum value for instance.</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">From what I understand in indirected enum cases the compiler will basically just box either</div><div class=""><ul class=""><li class="">the case value as a whole or</li><li class="">just the associative values which cause the recursion.</li></ul><div class="">What is boxed?</div></div></div></div></blockquote><div><br class=""></div>Applying the ‘indirect’ keyword to the enum has the same effect as applying it to all payload cases. In both instances, the enum case discriminator is stored as part of the value, and not inside the box.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">I do not intend to propose to make <font face="monospace, monospace" class="">indirect</font> part of the type itself. I'm checking whether the modifier can be moved closer to the declaration of the variables which cause the indirections.</div></div></div></blockquote><div><br class=""></div>Basically, the problem is the type of an enum payload is a single value, which may be a tuple. So if indirect can appear inside this tuple, it’s part of the type, because it becomes possible to get a value whose type is the type of the payload, with the indirect and all.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="">What I need for my proposal is indeed indirection on structs and for that I'd like to understand how indirections work under the hood and what their limitations are.</div><div class="">Your answer already gives a lot of insight there.</div><div class=""><br class=""></div><div class="">Actually I once needed to <a href="https://gist.github.com/fluidsonic/6a8f1c1def2a92416519" class="">design a recursive struct</a> and did so by just wrapping the recursive variable in an indirect enum case. Works fine in Swift 2.1</div><div class="">I could have done it differently - e.g. by storing an array of parents instead of using recursion - but the approach worked.</div><div class=""><br class=""></div><div class="">How can a recursive struct using indirection be an infinite type? Since the indirect variables are just boxes which have a fixed size (just a pointer?) independent of the struct's size the type is no longer infinite.</div></div></div></blockquote><div><br class=""></div>Yes, but each indirect box has to have a value. So for example, this is invalid, whether or not the property is ‘indirect’ — DI would require S.s be initialized to a value of type S in the constructor, which in turn has to be initialized, leading to an infinite chain S.s.s.s.s… of values.</div><div><br class=""></div><div>struct S {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>let s: S</div><div>}</div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">Thanks,</div><div class="">&nbsp; Marc</div><div class=""><br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Fri, Dec 11, 2015 at 4:03 PM, Slava Pestov <span dir="ltr" class="">&lt;<a href="mailto:spestov@apple.com" target="_blank" class="">spestov@apple.com</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="">Hi Marc,<div class=""><br class=""><div class=""><span class=""><blockquote type="cite" class=""><div class="">On Dec 11, 2015, at 3:06 AM, Marc Knaup via swift-dev &lt;<a href="mailto:swift-dev@swift.org" target="_blank" class="">swift-dev@swift.org</a>&gt; wrote:</div><br class=""><div class=""><div dir="ltr" class="">Hey guys,<div class=""><br class=""></div><div class="">I'm working on a proposal and the question arose why the declaration modifier <font face="monospace, monospace" class="">indirect</font> can only be specified for the whole enum&nbsp;<font face="monospace, monospace" class="">case</font> and the whole <font face="monospace, monospace" class="">enum</font> but not for the actual parameter which is indirect.</div><div class=""><br class=""></div><div class="">I.e. is there any technical reason which would prevent something like the following?</div><div class=""><br class=""></div><div class=""><ol style="border:0px;font-size:14px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;line-height:1.6em;list-style:none;font-family:Helvetica,Arial,sans-serif;background-repeat:initial initial" class=""><li style="border-width:0px 0px 0px 18px;border-left-style:solid;border-left-color:transparent;margin:0px;outline:0px;padding:0px 10px 0px 0px;vertical-align:baseline;white-space:pre-wrap;list-style-type:none;background:transparent" class=""><code style="border:0px;font-size:0.85em;margin:0px;outline:0px;padding:0px;vertical-align:baseline;font-family:Menlo,monospace;word-wrap:break-word;background:transparent" class=""><span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(170,51,145);background:transparent" class="">enum</span> <span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">ArithmeticExpression</span> {</code></li><li style="border-width:0px 0px 0px 18px;border-left-style:solid;border-left-color:transparent;margin:0px;outline:0px;padding:0px 10px 0px 0px;vertical-align:baseline;white-space:pre-wrap;list-style-type:none;background:transparent" class=""><code style="border:0px;font-size:0.85em;margin:0px;outline:0px;padding:0px;vertical-align:baseline;font-family:Menlo,monospace;word-wrap:break-word;background:transparent" class="">    <span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(170,51,145);background:transparent" class="">case</span> <span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">Number</span>(<span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">Int</span>)</code></li><li style="border-width:0px 0px 0px 18px;border-left-style:solid;border-left-color:transparent;margin:0px;outline:0px;padding:0px 10px 0px 0px;vertical-align:baseline;white-space:pre-wrap;list-style-type:none;background:transparent" class=""><code style="border:0px;font-size:0.85em;margin:0px;outline:0px;padding:0px;vertical-align:baseline;font-family:Menlo,monospace;word-wrap:break-word;background:transparent" class="">    <span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(170,51,145);background:transparent" class="">case</span> <span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">Addition</span>(<span style="color:rgb(170,51,145);font-size:11.9px;line-height:22.4px" class="">indirect </span><span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">ArithmeticExpression</span>, <span style="color:rgb(170,51,145);font-size:11.9px;line-height:22.4px" class="">indirect </span><span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">ArithmeticExpression</span>)</code></li><li style="border-width:0px 0px 0px 18px;border-left-style:solid;border-left-color:transparent;margin:0px;outline:0px;padding:0px 10px 0px 0px;vertical-align:baseline;white-space:pre-wrap;list-style-type:none;background:transparent" class=""><code style="border:0px;font-size:0.85em;margin:0px;outline:0px;padding:0px;vertical-align:baseline;font-family:Menlo,monospace;word-wrap:break-word;background:transparent" class="">    <span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(170,51,145);background:transparent" class="">case</span> <span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">Multiplication</span>(<span style="color:rgb(170,51,145);font-size:11.9px;line-height:22.4px" class="">indirect </span><span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">ArithmeticExpression</span>, <span style="color:rgb(170,51,145);font-size:11.9px;line-height:22.4px" class="">indirect </span><span style="border:0px;font-size:11.9px;margin:0px;outline:0px;padding:0px;vertical-align:baseline;color:rgb(63,110,116);background:transparent" class="">ArithmeticExpression</span>)</code></li><li style="border-width:0px 0px 0px 18px;border-left-style:solid;border-left-color:transparent;margin:0px;outline:0px;padding:0px 10px 0px 0px;vertical-align:baseline;white-space:pre-wrap;list-style-type:none;background:transparent" class=""><code style="border:0px;font-size:0.85em;margin:0px;outline:0px;padding:0px;vertical-align:baseline;font-family:Menlo,monospace;word-wrap:break-word;background:transparent" class="">}</code></li></ol></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">Right now, notice that direct and indirect cases look the same from the perspective of the type system.</div><div class=""><br class=""></div>With your proposal, the fact that the entire tuple payload can be matched by a pattern implies that ‘indirect’ has to become a formal type in the language, since you will now be able to write down a value of type '(indirect ArithmeticExpression, Int)’, for example. It also raises the issue of how these indirect values are wrapped and unwrapped, since now the ‘indirect ArithmeticExpression’ is itself a value.</div><div class=""><br class=""></div><div class="">An alternative is to make ‘indirect’ a non-materializable type, like ‘inout’. ‘inout’ can appear inside tuple types, but is not a first class value. This creates lots of special cases for ‘inout’ and you can imagine it will be equally difficult for ‘indirect’.</div><div class=""><br class=""></div><div class="">If you want an ‘indirect’ that can be nested inside a tuple type, you could just define ‘class Box&lt;T&gt; { let payload: T }’ and tolerate a bit of verbosity when wrapping and unwrapping values. As long as the payload is immutable, you will still have value semantics using this trick.</div><div class=""><span class=""><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><div class=""><br class=""></div><div class="">Also is there any technical reason which would prevent <font face="monospace, monospace" class="">indirect</font> from being used for structs?</div></div></div></div></blockquote><div class=""><br class=""></div></span>Like an ‘indirect’ modifier for stored properties on structs? Yes, this should be possible, however note that right now enum payloads are not themselves lvalues, which means that assignment of indirect enum cases only has to update the reference count of the box to maintain value semantics, since the contents of the box will never change. Presumably for structs you would need to be able to define an ‘indirect var’ with a mutable payload — immutable-only indirect stored properties don’t seem very useful.</div><div class=""><br class=""></div><div class="">Making the indirect payload mutable will require either copying the box upon assignment, or alternatively, a copy-on-write scheme could be used. The SIL @box type that implements indirect cases isn’t set up to support either of those right now. Also, unlike enums, indirect fields of structs won’t give you any new generality that was not possible before — its just a performance change. A value type that contains a cycle through an ‘indirect’ struct field is still invalid, for example, because the resulting type is still infinite.</div><div class=""><br class=""></div><div class="">Slava</div><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><div class=""><br class=""></div>Thanks,</div><div class="">&nbsp; Marc</div></div>
<img src="https://u2002410.ct.sendgrid.net/wf/open?upn=NLTid1W7V2mxBEfr5Y3KfTntaxSmOQp5vjACZc9Eh1-2FH-2Fej3R0Z4mS437WqlI1ZHGDmechBex8wNnLcJAHS6eiylKs3WYt15t33yHp9mn7CB7YyRdAiuVdlIEZ5ZSycYp-2FI-2Fye5YAEe-2BJ4JGvHQKwIkodfRQ4j1PO0QRgL5XH9IBuZwtywxGv6RtPHTbFFl-2FWHkI317MHZLEjSP5REx3kUUnTjy4X4Zqh4JcvTGKFv0-3D" alt="" width="1" height="1" border="0" style="min-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="">
_______________________________________________<br class="">swift-dev mailing list<br class=""><a href="mailto:swift-dev@swift.org" target="_blank" class="">swift-dev@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-dev" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-dev</a><br class=""></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></body></html>