1

I am trying to create a generic Queue class that has an average function however I am having trouble doing so because I need a protocol that somehow says that T(Int) is a valid operation.

This was my attempt

class Queue<T:Numeric & Comparable> {
    private var array:[T]
    .....
    func average() -> T {
        return sum() / T(array.count)
    }
}

However for obvious reasons the compiler says that I cant do that because T does not support explicit initialization. What is the name of a protocol that implements this behavior or how can I code my own?

J.Doe
  • 1,502
  • 13
  • 47
  • You wouldn't really want this though, because the result will always be a whole number – Alexander Dec 31 '17 at 20:51
  • what types exactly do you want to store in your queue? only integers? or floating-point numbers? – Fyodor Volchyok Dec 31 '17 at 22:12
  • And why do you need to create T based on `array.count`? It doesn't make sense to me. You want conversion of division to be of type T? How could it be possible? How can result of division be always integer, for example? And why do you need average to be T? Wouldn't it be enough if `average()` always returns float? – Fyodor Volchyok Dec 31 '17 at 22:22
  • @FyodorVolchyok It's entirely possible that T could be of a type that support initialization from an `Int` (`array.count`). The code can be written so as to always return an `Int` average, although that would cause truncation – Alexander Dec 31 '17 at 23:07
  • @Alexander I understand that this code could be written. But that doesn't make it more sensible. And I don't understand situations where you'd need rounded (in which way?) average of some _generic_ numeric array. Or such rounding should be clearly defined in documentation or obvious from method name (for example). – Fyodor Volchyok Dec 31 '17 at 23:27
  • @FyodorVolchyok Yeah, I agree, but that's not what you wrote: " How could it be possible?" – Alexander Jan 01 '18 at 19:16

1 Answers1

1

Note that Numeric Protocol also includes FloatingPoint types, so you should constrain your Queue generic type to BinaryInteger. And regarding your average return type you should return Double instead of the generic integer. Your Queue class should look like this:

class Queue<T: BinaryInteger & Comparable> {
    private var array: [T] = []
    init(array: [T]) {
        self.array = array
    }
    func sum() -> T {
        return array.reduce(0, +)
    }
    func average() -> Double {
        return array.isEmpty ? 0 : Double(Int(sum())) / Double(array.count)
    }

    // If you would like your average to return the generic type instead of Double you can use numericCast method which traps on overflow and converts a value when the destination type can be inferred from the context.
    // func average() -> T {
    //     return sum() / numericCast(array.count)
    // }

}

Playground Testing

let queue = Queue(array: [1,2,3,4,5])
queue.sum()       // 15
queue.average()   // 3

If you would like to extend an array of Numeric, BinaryInteger or FloatingPoint types you can check this answer.

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571