Experimenting with conditional conformances

I’have a protocol:

protocol Inertial {
  func convexHull( _ t:AffineTransform? ) -> [CGPoint]
  func area( _ t:AffineTransform? ) -> CGFloat
  func firstOrderMomentums( _ t:AffineTransform? ) -> (x:CGFloat,y:CGFloat)
  func secondOrderMomentums( _ t:AffineTransform? ) -> (xx:CGFloat,xy:CGFloat,yy:CGFloat)
}

I make [CPoint] (a poligon) conforms to the protocol:

extension Array : Inertial where Element == CGPoint {
    func convexHull(_ t: AffineTransform?) -> [CGPoint] {
        return ConvexHull.convexHull( points:self ).map { $0 * t }
    }
    
    func area(_ t: AffineTransform?) -> CGFloat {
        return InertialUti.area( polig: self,t )
    }
    
    func firstOrderMomentums(_ t: AffineTransform?) -> (x: CGFloat, y: CGFloat) {
        return InertialUti.firstOrderMomentums( polig:self,t )
    }
    
    func secondOrderMomentums(_ t: AffineTransform?) -> (xx: CGFloat, xy: CGFloat, yy: CGFloat) {
        return InertialUti.secondOrderMomentums( polig:self,t )
    }
}

and work like a charm.

Then I try to make [[CPoint]] (an array of poligons) conforms to the same protocol:

extension Array : Inertial where Element == [CGPoint] {
    var allVertexs : [CGPoint] {
        return flatMap({$0})
    }
    
    func convexHull(_ t: AffineTransform?) -> [CGPoint] {
        return ConvexHull.convexHull( points:allVertexs ).map { $0 * t }
    }
    
    func area(_ t: AffineTransform?) -> CGFloat {
        return InertialUti.area( poligs: self,t )
    }
    
    func firstOrderMomentums(_ t: AffineTransform?) -> (x: CGFloat, y: CGFloat) {
        return InertialUti.firstOrderMomentums( poligs:self,t )
    }
    
    func secondOrderMomentums(_ t: AffineTransform?) -> (xx: CGFloat, xy: CGFloat, yy: CGFloat) {
        return InertialUti.secondOrderMomentums( poligs:self,t )
    }
}

but this isn’t permitted: Redundant conformance of 'Array<Element>' to protocol ‘Inertial’ !

I think it's a severe limitation: array with different element’s type (i.e. different specializations of the same generic type) should be treated as distinct types and not as the same type.

Hi Antonio,

This is explicitly mentioned in the original proposal. We do not allow multiple conditional conformances to be defined for the same type. Instead, is it possible to express your conformance as follows?

extension Array : Intertial where Element : Inertial { … }

Or do you really need different algorithms for Element == CGPoint and Element == [CGPoint], with no conformance for Element == [[CGPoint]], etc?

If the latter, you could possibly have an InertialElement protocol or similar that CGPoint and [CGPoint] conform to, with a second level of dispatch to pick between the two cases.

Slava

···

On Nov 28, 2017, at 12:31 PM, Antonino Ficarra via swift-users <swift-users@swift.org> wrote:

I’have a protocol:

protocol Inertial {
  func convexHull( _ t:AffineTransform? ) -> [CGPoint]
  func area( _ t:AffineTransform? ) -> CGFloat
  func firstOrderMomentums( _ t:AffineTransform? ) -> (x:CGFloat,y:CGFloat)
  func secondOrderMomentums( _ t:AffineTransform? ) -> (xx:CGFloat,xy:CGFloat,yy:CGFloat)
}

I make [CPoint] (a poligon) conforms to the protocol:

extension Array : Inertial where Element == CGPoint {
    func convexHull(_ t: AffineTransform?) -> [CGPoint] {
        return ConvexHull.convexHull( points:self ).map { $0 * t }
    }
    
    func area(_ t: AffineTransform?) -> CGFloat {
        return InertialUti.area( polig: self,t )
    }
    
    func firstOrderMomentums(_ t: AffineTransform?) -> (x: CGFloat, y: CGFloat) {
        return InertialUti.firstOrderMomentums( polig:self,t )
    }
    
    func secondOrderMomentums(_ t: AffineTransform?) -> (xx: CGFloat, xy: CGFloat, yy: CGFloat) {
        return InertialUti.secondOrderMomentums( polig:self,t )
    }
}

and work like a charm.

Then I try to make [[CPoint]] (an array of poligons) conforms to the same protocol:

extension Array : Inertial where Element == [CGPoint] {
    var allVertexs : [CGPoint] {
        return flatMap({$0})
    }
    
    func convexHull(_ t: AffineTransform?) -> [CGPoint] {
        return ConvexHull.convexHull( points:allVertexs ).map { $0 * t }
    }
    
    func area(_ t: AffineTransform?) -> CGFloat {
        return InertialUti.area( poligs: self,t )
    }
    
    func firstOrderMomentums(_ t: AffineTransform?) -> (x: CGFloat, y: CGFloat) {
        return InertialUti.firstOrderMomentums( poligs:self,t )
    }
    
    func secondOrderMomentums(_ t: AffineTransform?) -> (xx: CGFloat, xy: CGFloat, yy: CGFloat) {
        return InertialUti.secondOrderMomentums( poligs:self,t )
    }
}

but this isn’t permitted: Redundant conformance of 'Array<Element>' to protocol ‘Inertial’ !

I think it's a severe limitation: array with different element’s type (i.e. different specializations of the same generic type) should be treated as distinct types and not as the same type.

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

There are different algorithms for Element==CGPoint, Element==[CGPoint], Element==[AreaPoint], etc…

Your second suggestion work:

protocol Inertial {
  func convexHull( _ t:AffineTransform? ) -> [CGPoint]
  func area( _ t:AffineTransform? ) -> CGFloat
  func firstOrderMomentums( _ t:AffineTransform? ) -> (x:CGFloat,y:CGFloat)
  func secondOrderMomentums( _ t:AffineTransform? ) -> (xx:CGFloat,xy:CGFloat,yy:CGFloat)
}

protocol InertialElement {
  static func convexHull( elements:[Self], _ t: AffineTransform?) -> [CGPoint]
  static func area( elements:[Self],_ t: AffineTransform?) -> CGFloat
  static func firstOrderMomentums( elements:[Self],_ t: AffineTransform?) -> (x: CGFloat, y: CGFloat)
  static func secondOrderMomentums( elements:[Self],_ t: AffineTransform?) -> (xx: CGFloat, xy: CGFloat, yy: CGFloat)
}

extension Array : Inertial where Element : InertialElement {
  func convexHull(_ t: AffineTransform?) -> [CGPoint] {
    return Element.convexHull(elements: self, t)
  }
  
  func area(_ t: AffineTransform?) -> CGFloat {
    return Element.area(elements: self, t)
  }
  
  func firstOrderMomentums(_ t: AffineTransform?) -> (x: CGFloat, y: CGFloat) {
    return Element.firstOrderMomentums(elements: self, t)
  }
  
  func secondOrderMomentums(_ t: AffineTransform?) -> (xx: CGFloat, xy: CGFloat, yy: CGFloat) {
    return Element.secondOrderMomentums(elements: self, t)
  }
}

and than:

extension CGPoint : InertialElement {
  static func convexHull( elements:[CGPoint], _ t: AffineTransform?) -> [CGPoint] {
    return ConvexHull.convexHull( points:elements ).map { $0 * t }
  }
  
  static func area( elements:[CGPoint],_ t: AffineTransform?) -> CGFloat {
    return InertialUti.area( polig: elements,t )
  }
  
  static func firstOrderMomentums( elements:[CGPoint],_ t: AffineTransform?) -> (x: CGFloat, y: CGFloat) {
    return InertialUti.firstOrderMomentums( polig:elements,t )
  }
  
  static func secondOrderMomentums( elements:[CGPoint],_ t: AffineTransform?) -> (xx: CGFloat, xy: CGFloat, yy: CGFloat) {
    return InertialUti.secondOrderMomentums( polig:elements,t )
  }
}

extension Array : InertialElement where Element == CGPoint {
  ...
}

extension AreaPoint : InertialElement {
  ...
}

etc...

Thanks, Slava. :slight_smile:

Antonino

···

Il giorno 28 nov 2017, alle ore 23:17, Slava Pestov <spestov@apple.com> ha scritto:

Hi Antonio,

This is explicitly mentioned in the original proposal. We do not allow multiple conditional conformances to be defined for the same type. Instead, is it possible to express your conformance as follows?

extension Array : Intertial where Element : Inertial { … }

Or do you really need different algorithms for Element == CGPoint and Element == [CGPoint], with no conformance for Element == [[CGPoint]], etc?

If the latter, you could possibly have an InertialElement protocol or similar that CGPoint and [CGPoint] conform to, with a second level of dispatch to pick between the two cases.

Slava