Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referencing instance method 'stringify()' on 'Collection' requires the types 'Int' and 'Stringify' be equivalent

I made an protocol Stringify to convert Types that implement the protocol to a String.

protocol Stringify {
    func stringify() -> String
}

extension Collection where Iterator.Element == Stringify {
    /// changes all the elements in the collection to a String
    func stringify() -> [String] {
        var strings = [String]()
        if let elements = self as? [Stringify] {
            for element in elements {
                strings.append(element.stringify())
            }
        }
        return strings
    }
}

extension Int: Stringify {
    func stringify() -> String {
        return String(self)
    }
}

extension Double: Stringify {
    func stringify() -> String {
        return String(self)
    }
}


let test = [5,6,7]

/// does work
[6,5,34].stringify()


/// does not work -> Error alert
test.stringify()

But when I set a collection of Ints to a property and using then stringify() on it, it does not work.

Error:

Referencing instance method 'stringify()' on 'Collection' requires the types 'Int' and 'Stringify' be equivalent

If I use it directly everything is going fine.

What is the problem here?

like image 284
PaFi Avatar asked Mar 04 '23 17:03

PaFi


1 Answers

extension Collection where Iterator.Element == Stringify 

has a “same type requirement” and defines an extension for collections whose elements are of the type Stringify. But test is an array of Int, i.e. the elements conform to the Stringify protocol. So what you want is

extension Collection where Iterator.Element : Stringify

or, equivalently,

extension Collection where Element : Stringify

The reason that

/// does work
[6,5,34].stringify()

compiles with your original definition is that the compiler infers the type of the array as [Stringify] from the context.

let test: [Stringify] = [5,6,7]
test.stringify()

would compile as well.


Note that there is no need to cast self in the extension method. You can simplify the implementation to

func stringify() -> [String] {
    var strings = [String]()
    for element in self {
        strings.append(element.stringify())
    }
    return strings
}

or just

func stringify() -> [String] {
    return self.map { $0.stringify() }
}
like image 163
Martin R Avatar answered Apr 27 '23 09:04

Martin R