[swift-evolution] Brainstorming: New operator type - chaining

Jonathan Tang jonathan.d.tang at gmail.com
Sun Jan 31 17:51:06 CST 2016

On Sat, Jan 30, 2016 at 9:20 PM, Chris Lattner via swift-evolution <
swift-evolution at swift.org> wrote:

> On Jan 30, 2016, at 3:06 PM, Joseph Lord via swift-evolution <
> swift-evolution at swift.org> wrote:
> > Use case 2 - Chaining on custom types
> >
> > 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):
> 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.
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.

1. JQuery, where the state is a selection of DOM elements and each method
call is an operation on the DOM.
2. Builder pattern in Java, where the Builder holds the internal state of
the object and each method call validates that it's a legal transformation.
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.
4. Django'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.
5. BeautifulSoup, where the state is your current position in the DOM tree
and selection of nodes.

Swift is already a huge leap forward from Objective-C in this regard,
because the latter's syntax didn't really allow method chaining.

What optional chaining gives us is the ability to invoke an arbitrary
method of the "contained" object, without needing to know what type it is.
So for example, foo?.bar()?.baz() will invoke .bar() on Optional<Foo>
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.

I see this as being much more related to generics than protocols, though I
guess you'd need a protocol to specify the behavior of ? in terms of the
container type.  Use-cases I can think of:

1. Implicit mapping over collections, like JQuery.  myArray?.foo() would
invoke foo() on every object contained in myArray.
2. RPCs.  You could imagine RPCStub<RemoteObject> be an object that wraps
RemoteObject, and then stub?.foo(1, "two") 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'd get a lot more type-safety than stub.call("foo", 1, "two").
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.
4. Type erasure.  Right now, if Foo is a protocol with an associated type,
you can'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.
5. Anything that you'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.
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.

Now that I've listed them out, it's basically aspect-oriented programming,
which means it'd have the same use-cases as AOP and also the same pitfalls.

> 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.
> -Chris
> >
> > It would be good for code like the following to be possible (hopefully
> with a little more type inference).
> >
> > let c:Either<Int, Error> = Either<String, Error>(.Left(“boo"))^^.count
> >
> > Now the user’s definition of the operator would probably have to look
> something like this:
> >
> > func ^^<A,B, C>(lhs: Either<A,B>)->(ChainValueResult<A, C, Either<C,B>>
>  {
> >       switch lhs {
> >       case .Left(let a):
> >               return .continue(a, { Either<C,B>(.Left($0) })
> >        case .Right(let b):
> >               return .stop( Either<C, B>(.Right(b))
> >       }
> > }
> >
> > I couldn't find any significant discussion of optional chaining in the
> mailing list so far.
> >
> > Joseph
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160131/06943dc5/attachment.html>

More information about the swift-evolution mailing list