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

Joseph Lord joseph at human-friendly.com
Sat Jan 30 20:23:36 CST 2016


On 31/01/2016 01:14, Howard Lovatt via swift-evolution wrote:
 > What is wrong with flatMap returning an Optional? Like Scala does.
 >

Using map or a function taking a closure is less clear to read than an 
chaining mechanism.

For the first usecase (which is really the most trivial case of optional 
chaining:

 >     assert(foo != nil)
 >     foo?.bar()
 >
 >     I would only want to do:
 >
 >     foo±.bar()
 >

_ = foo.aMap { $0.bar() }

If you can image a multiple step chain it could clearly get more 
complicated.

I don't think that there is a way to avoid the closures within current 
Swift and any map/flatMap based approach.

I'm not familiar with Scala so I may have misunderstood exactly what you 
meant.

Joseph


> On Sunday, 31 January 2016, Joseph Lord via swift-evolution
> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>
>     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
>     _______________________________________________
>     swift-evolution mailing list
>     swift-evolution at swift.org
>     https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> --
>    -- Howard.
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>


-- 
Human Friendly Ltd.


More information about the swift-evolution mailing list