<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Jan 30, 2016 at 9:20 PM, Chris Lattner via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Jan 30, 2016, at 3:06 PM, Joseph Lord via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br>
&gt; Use case 2 - Chaining on custom types<br>
&gt;<br>
&gt; And this especially may not be feasible and I may be out of my depth describing the requirement but it feels like a more general case so at least worth airing):<br>
<br>
</span>I’m not certain I understand the problem you’re looking to solve here, but I think it would be great (though probably very low priority) to open up the functionality of the postfix optional chaining operator to other types.  This could allow its monadic binding (aka railroad short circuiting) behavior to be extended to other types like Result, a left-biased-either, or an arbitrary type defined by the user.  A natural approach would be to capture this behavior in an “chainable” protocol of some sort.<br>
<br></blockquote><div><br></div><div>BTW, chainable monadic behavior is already available via .method() calls on an object that returns Self and maintains some internal state.  This is widely used across a number of other languages, eg.</div><div><br></div><div>1. JQuery, where the state is a selection of DOM elements and each method call is an operation on the DOM.</div><div>2. Builder pattern in Java, where the Builder holds the internal state of the object and each method call validates that it&#39;s a legal transformation.</div><div>3. SwiftyJSON, where the state is whether every key along the chain exists and has the proper type, and then .stringValue/.intValue/.boolValue returns the final result or nil if there was an error at any point.</div><div>4. Django&#39;s ORM, where the state is the current clauses of the SQL query, each method adds a clause, and then subscripting/iterating/etc. force query-building and execution of the query.</div><div>5. BeautifulSoup, where the state is your current position in the DOM tree and selection of nodes.</div><div><br></div><div>Swift is already a huge leap forward from Objective-C in this regard, because the latter&#39;s syntax didn&#39;t really allow method chaining.</div><div><br></div><div>What optional chaining gives us is the ability to invoke an arbitrary method of the &quot;contained&quot; object, without needing to know what type it is.  So for example, foo?.bar()?.baz() will invoke .bar() on Optional&lt;Foo&gt; without Optional having to explicitly say that it supports a method bar().  It just forwards all operations on, providing nil if the Optional contained nil.  Sorta like a type-safe version of #doesNotUnderstand in SmallTalk.</div><div><br></div><div>I see this as being much more related to generics than protocols, though I guess you&#39;d need a protocol to specify the behavior of ? in terms of the container type.  Use-cases I can think of:</div><div><br></div><div>1. Implicit mapping over collections, like JQuery.  myArray?.foo() would invoke foo() on every object contained in myArray.</div><div>2. RPCs.  You could imagine RPCStub&lt;RemoteObject&gt; be an object that wraps RemoteObject, and then stub?.foo(1, &quot;two&quot;) marshals the parameters, passes them along to the remove server, invokes them, and returns them, maybe wrapped in a Promise.  Assuming the remote object is written in Swift too, you&#39;d get a lot more type-safety than stub.call(&quot;foo&quot;, 1, &quot;two&quot;).</div><div>3. Logging/tracing/performance monitoring, where you might want to record the fact that the call was made without worrying about what call it is.</div><div>4. Type erasure.  Right now, if Foo is a protocol with an associated type, you can&#39;t have an array of Foo where each element might be a different concrete type adopting Foo.  The typical workaround is a struct AnyFoo which wraps the concrete instance, adopts Foo, and forwards all calls on to the wrapped instance.  A chaining operator would let you avoid having to explicitly adopt the protocol and write all the forwarding message calls.</div><div>5. Anything that you&#39;d use ES6 proxy objects for.  I had a use-case for these a couple months ago that involved tracking everything that was stored in a container so the container could be automatically persisted.</div><div>6. CoreData could possibly benefit from this - imagine being able to define CoreData objects as ordinary Swift structs, intercept all property setting, and use this to build the appropriate ManagedObjectModels.   A lot of the current model-editing GUI in XCode might be able to be replaced.</div><div><br></div><div>Now that I&#39;ve listed them out, it&#39;s basically aspect-oriented programming, which means it&#39;d have the same use-cases as AOP and also the same pitfalls.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
This is low priority because I don’t know a lot of killer applications of it, I’m motivated by my ivory tower desire to push compiler magic into the standard library.  It bugs me that optional has sugar and other behavior that other types can’t participate in.<br>
<br>
-Chris<br>
<div class="HOEnZb"><div class="h5"><br>
&gt;<br>
&gt; It would be good for code like the following to be possible (hopefully with a little more type inference).<br>
&gt;<br>
&gt; let c:Either&lt;Int, Error&gt; = Either&lt;String, Error&gt;(.Left(“boo&quot;))^^.count<br>
&gt;<br>
&gt; Now the user’s definition of the operator would probably have to look something like this:<br>
&gt;<br>
&gt; func ^^&lt;A,B, C&gt;(lhs: Either&lt;A,B&gt;)-&gt;(ChainValueResult&lt;A, C, Either&lt;C,B&gt;&gt;   {<br>
&gt;       switch lhs {<br>
&gt;       case .Left(let a):<br>
&gt;               return .continue(a, { Either&lt;C,B&gt;(.Left($0) })<br>
&gt;        case .Right(let b):<br>
&gt;               return .stop( Either&lt;C, B&gt;(.Right(b))<br>
&gt;       }<br>
&gt; }<br>
&gt;<br>
&gt; I couldn&#39;t find any significant discussion of optional chaining in the mailing list so far.<br>
&gt;<br>
&gt; Joseph<br>
&gt; _______________________________________________<br>
&gt; swift-evolution mailing list<br>
&gt; <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
&gt; <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
<br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</div></div></blockquote></div><br></div></div>