<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></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 Jun 28, 2017, at 5:33 AM, Dimitri Racordon via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Using our contextual variables, one could rewrite our motivational example as follows:</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span class="" style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">class</span><span class="" style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;"> Interpreter: </span><span class="" style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Visitor</span><span class="" style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;"> {</span></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> visit(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">_</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> node: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">BinExpr</span><span class="" style="font-variant-ligatures: no-common-ligatures;">) {</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> <span class="" style="color: rgb(186, 45, 162);">let</span> lhs, rhs : </span><span class="" style="color: rgb(112, 61, 170);">Int</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-tab-span" style="white-space: pre;"></span><span class="" style="color: rgb(186, 45, 162);">set</span> accumulator = <span class="" style="color: rgb(186, 45, 162);">nil</span> <font color="#ba2da2" class="">in</font> {</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures;">node.lhs.accept(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">self</span><span class="" style="font-variant-ligatures: no-common-ligatures;">)</span></div><div class="" style="margin: 0px; line-height: normal;"> lhs = accumulator!</div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> }</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-tab-span" style="white-space: pre;"></span><span class="" style="color: rgb(186, 45, 162);">set</span> accumulator = <span class="" style="color: rgb(186, 45, 162);">nil</span> </span><font color="#ba2da2" class="">in </font>{</div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures;">node.lhs.accept(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">self</span><span class="" style="font-variant-ligatures: no-common-ligatures;">)</span></div><div class="" style="margin: 0px; line-height: normal;"> rhs = accumulator!</div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> }</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;"><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">switch</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> node.op {</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">case</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"+"</span><span class="" style="font-variant-ligatures: no-common-ligatures;">:</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> accumulator = lhs + rhs</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">case</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"-"</span><span class="" style="font-variant-ligatures: no-common-ligatures;">:</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> accumulator = lhs - rhs</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">default</span><span class="" style="font-variant-ligatures: no-common-ligatures;">:</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> fatalError(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"unexpected operator </span><span class="" style="font-variant-ligatures: no-common-ligatures;">\</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">(</span><span class="" style="font-variant-ligatures: no-common-ligatures;">node.op</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">)"</span><span class="" style="font-variant-ligatures: no-common-ligatures;">)</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> }</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> }</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> visit(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">_</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> node: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Literal</span><span class="" style="font-variant-ligatures: no-common-ligatures;">) {</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> accumulator = node.val</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> }</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><div class="" style="margin: 0px; line-height: normal; min-height: 13px;"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);"> func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> visit(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">_</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> node: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Scope</span><span class="" style="font-variant-ligatures: no-common-ligatures;">) {</span></div><div class="" style="margin: 0px; line-height: normal; min-height: 13px;"><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-tab-span" style="white-space: pre;"></span><span class="" style="color: rgb(186, 45, 162);">set</span> symbols = [:]</span> <font color="#ba2da2" class="">in</font> {</div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">for</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> child </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">in</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> node.children {</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> child.accept(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">self</span><span class="" style="font-variant-ligatures: no-common-ligatures;">)</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> }</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> }</span></div></div><div class="" style="margin: 0px; line-height: normal; min-height: 13px;"> }</div></span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> visit(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">_</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> node: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Identifier</span><span class="" style="font-variant-ligatures: no-common-ligatures;">) {</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">guard</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">let</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> val = symbols?[node.name] <span class="" style="color: rgb(186, 45, 162);">else</span> {</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures;">fatalError(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"undefined symbol</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">: </span><span class="" style="font-variant-ligatures: no-common-ligatures;">\</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">(</span><span class="" style="font-variant-ligatures: no-common-ligatures;">node.name</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">)</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"</span><span class="" style="font-variant-ligatures: no-common-ligatures;">)</span></div><div class="" style="margin: 0px; line-height: normal;"> }</div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span>accumulator = val</div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> }</span></div></span></div></span></div></div></span></div><div class="" style="margin: 0px; line-height: normal; min-height: 13px;"><span class="" style="font-variant-ligatures: no-common-ligatures;"></span><br class=""></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);">context var</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> accumulator: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Int</span><span class="" style="font-variant-ligatures: no-common-ligatures;">?</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);"> context</span></span><span class="" style="color: rgb(186, 45, 162);"> </span><span class="" style="color: rgb(186, 45, 162);">var</span> symbols: [String: Int]?</div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;">}</span></div><div class=""><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div></div></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">It is no longer unclear what depth of the tree the <font face="Menlo" class="" style="font-size: 11px;">accumulator</font> variable should be associated with. The mechanism is handled automatically, preventing the programmer from incorrectly reading a value that was previously set for another descent. It is no longer needed to manually handle the stack management of the <span class="" style="font-family: Menlo; font-size: 11px;">symbols</span> variable, which was error prone in our previous implementation.</div></div></blockquote><br class=""></div><div>As far as I can see, you can do this with existing features:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>struct Contextual<Value> {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> private var values: [Value]</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> </div><div><span class="Apple-tab-span" style="white-space:pre">        </span> var value: Value {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> get { return values.last! }</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> set { values[values.index(before: values.endIndex)] = newValue }</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> }</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> </div><div><span class="Apple-tab-span" style="white-space:pre">        </span> mutating func with<R>(_ value: Value, do body: () throws -> R) rethrows -> R {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> values.append(value)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> defer { values.removeLast() }</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> return try body()</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> }</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span> class Interpreter: Visitor {</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span> var accumulator: Contextual<Int?><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> var symbols: Contextual<[String: Int]></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> func visit(_ node: BinExpr) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> let lhs, rhs : Int<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> accumulator.with(nil) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> node.lhs.accept(self)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> lhs = accumulator.value!<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> accumulator.with(nil) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> node.lhs.accept(self)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> rhs = accumulator.value!<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> switch node.op {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> case "+":<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> accumulator.value = lhs + rhs<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> case "-":<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> accumulator.value = lhs - rhs<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> default:<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> fatalError("unexpected operator \(node.op)")<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> func visit(_ node: Literal) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> accumulator.value = node.val<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> func visit(_ node: Scope) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> symbols.with([:]) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> for child in node.children {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> child.accept(self)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> func visit(_ node: Identifier) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> guard let val = symbols.value[node.name] else {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> fatalError("undefined symbol: \(node.name)")<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> accumulator.value = val<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><br class=""></div><div>(There is actually a minor problem with this: the closures passed to `with(_:do:)` can't initialize `lhs` and `rhs` because DI can't prove they're run exactly once. I'd like an `@once` annotation on closure parameters to address this, but in the mean time, you can use `var` for those parameters instead of `let`.)<br class=""><br class=""></div><div>Obviously, your `context` keyword is slightly prettier to use. But is that enough? Is this use case *so* common, or the syntax of `with(_:do:)` and `value` *so* cumbersome, that it's worth adding language features to avoid it?</div><div><br class=""></div><div>And if the existing syntax *is* too cumbersome, could the Property Behaviors proposal (with some of the extensions described at the end) allow you to implement this yourself with an acceptable syntax? <<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md</a>></div><div><br class=""></div><div>Basically, what about this problem *requires* a solution built in to the language? Language-level solutions are difficult to design and have to be maintained forever, so it's going to take a lot to convince us this is a good addition to the language.</div><br class=""><div class="">
<span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;"><div class=""><div style="font-size: 12px; " class="">-- </div><div style="font-size: 12px; " class="">Brent Royal-Gordon</div><div style="font-size: 12px; " class="">Architechies</div></div></span>
</div>
<br class=""></body></html>