[swift-evolution] Generic types—covariance/contravariance

Daniel Leping daniel at crossroadlabs.xyz
Fri Dec 9 05:25:48 CST 2016


Huge +1 here.

To bring powerful functional approach to Swift I strongly feel like it's a
must have.

Issue demonstration:
//co/invariance type
typealias FooFun<-A, +R> = (A)->R
//current types
typealias BarFun<A, R> = (A)->R

func exact(view:UIView) -> UIView
func nonexact(view:NSObject) -> UIControl

//ok
let magicFoo1:FooFun<UIView, UIView> = exact
//ok
let magicFoo2:FooFun<UIView, UIView> = nonexact

//ok
let magicBar1:BarFun<UIView, UIView> = exact
//FAIL
let magicBar2:BarFun<UIView, UIView> = nonexact

The last one fails, though function nonexact can do the job perfectly and
there is no inconsistency as it accepts NSObject (UIView inherits from it
so we are safe) and gives back UIControl (which is a subclass of UIView).

There are other examples with classes and functional stuff, but I hope I
made the problem clear.


On Fri, 9 Dec 2016 at 2:46 Braeden Profile via swift-evolution <
swift-evolution at swift.org> wrote:

> Has the core team or the community considered the possibility of
> implementing covariant/contravariant generic types?  It would really be
> appreciated.
>
> I know with Array, vague-ifying or specific-ifying the type ([Int] to
> [Any]) has help from the compiler—and we can use `map` if all else
> fails—but that only lessens the impact of the missing functionality.  This
> is my exact use case here, using SceneKit to identify the first-hit
> Controller object:
>
> class ControllerNode<Controller: AnyObject>: SCNNode
> {
> let controller: Controller
> }
>
> // Ordered front to back, returns the first Controller object.
> for hit in hitTest
> {
> // Determine if this node is part of a controller.
> let ancestrySequence = sequence(first: hit.node, next: { $0.parent })
> * let lastControllerNode: ControllerNode<AnyObject>? =
> ancestrySequence.reduce(nil)*
> * { ($1 as? ControllerNode) ?? $0 }*
> if let cabinet = lastControllerNode?.controller as? CabinetController
> { return cabinet }
>
>
> if let wall = lastControllerNode?.controller as? WallController
> { return wall }
> }
>
> This compiles, but unfortunately, this will never work.  The `reduce`
> algorithm always ends up trying to convert things like
> `ControllerNode<WallController> as ControllerNode<AnyObject>`,
> which—unintuitively—always fails.  Without compiler help, so would things
> like `myIntArray as [Any]` or `Optional<Boy>(Boy()) as Optional<Human>`.
>
> If Swift is supposed to welcome generic programming, this would be a great
> thing to have.
> _______________________________________________
>
> 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/20161209/ddd5b8b4/attachment.html>


More information about the swift-evolution mailing list