[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