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

Joseph Lord joseph at human-friendly.com
Sat Jan 30 17:06:29 CST 2016


Currently there are three types of operator: prefix, infix and postfix 
and most of the Swift operations can be defined using these and 
implemented for additional types and they cover most use cases but there 
are features in the Swift language which cannot be replicated and 
customised with these.

In particular there is the optional chaining use of `?` for which I can 
see no way of producing customised versions of or adapting to types 
other than optionals (e.g. custom Either types or other monadic types).

I’m not sure about the feasibility of this change or what knockon 
effects might be. This is meant as exploratory suggestion that may not 
reach proposal stage.

Would be interested to know:
1) If this is feasible.
2) If it is interesting to people.
3) What if anything should be possible for l-values (optional chaining 
works on them but what should be possible.
4) Any other good alternatives.

I picture that the chaining operator function would be called with the 
left hand side value and could be required to return a value of a type 
such as this ChainValueResult:

enum ChainValueResult<A,C,D> {
   case continue(A, C->D),
   case stop(D)
}

The logic then applied to this enum would be in case of continue to 
apply the C->D function to the result of continuing the chain which is 
applied to the A value. In the case of stop it is to simply return the 
value of type D.

I have used this enum in the draft code below. Please note that the code 
below doesn't compile and that if really being used the inference system 
would need to account for the return type of the ongoing chain.

Use case 1 - Custom optional chaining behaviour

The particular thing that I would like use this for is to make a custom 
asserting variant of the optional chaining operator. I already do this 
with nil coalescing (it is currently the only custom operator in my 
code) but a shorthand for this would be good:

assert(foo != nil)
foo?.bar()

I would only want to do:

foo±.bar()

func ± <A, C>(lhs: A?)->ChainValueResult<A, C->C? ,C?> {
	if let lhs = lhs {
		return .continue(lhs, { $0 })
  	} else {
		assertionFailure()
	        return .stop(nil)
	}
}

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):

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


More information about the swift-evolution mailing list