2

Suppose I create a protocol and structure for a Column of homogeneously typed data:

protocol Columnizable {
    associatedtype Item

    var name: String { get }
    var values: [Item] { get }

}

struct Column<T>: Columnizable {

    var name: String
    var values = [T]()

}

I would like to create a Protocol extension that allows Numeric to have an average function that could compute the average of values if the type conforms to Numeric protocol- for instance, namely Double and Int

extension Columnizable where Item: Numeric {

    func average() -> Double {
        return Double(sum()) / values.count
    }

    func sum() -> Item {
        return values.reduce(0, +)
    }

}

My attempt at the average function cannot be compiled because of:

Cannot invoke initializer for type 'Double' with an argument list of type '(Self.item)'

Attempts to cast to Double do not work. Any advice for best practices here would be appreciated.

  • 3
    Possibly helpful: [Is there a way to convert any generic Numeric into a Double?](https://stackoverflow.com/q/53771879/1187415) – Martin R Jan 27 '19 at 18:23
  • 1
    If I created a `Complex` type that conformed to `Numeric` (which is quite straightforward to do), what would you want to happen here? Thinking through that case will likely lead you to the better answer. – Rob Napier Jan 27 '19 at 18:33
  • 2
    @MartinR https://stackoverflow.com/a/28288619/2019221 – Callam Jan 27 '19 at 19:18
  • 1
    Thank you guys, @Callam that solution was right on point. I did not know about `BinaryInteger` and `BinaryFloatingPoint`. – Robert F. Dickerson Jan 27 '19 at 19:46

1 Answers1

1

I needed to use the BinaryInteger or BinaryFloatingPoint protocols since they can easily be transformed to a Double. As @rob napier called out, that a Complex type would not be Double convertible.

extension Columnizable where Item: BinaryInteger {
    var average: Double {
        return Double(total) / Double(values.count)
    }
}

extension Columnizable where Item: BinaryFloatingPoint {
    var average: Item {
        return total / Item(values.count)
    }
}

stackoverflow.com/a/28288619/2019221