Tero Tolonen Tero Tolonen - 1 month ago 19
Swift Question

Swift 3 - Sequence ambiguous without more context

I tried to create a custom iterator which returns wrapper

abcContainer
over raw data class
abc


// raw data class
class abc {
var name : String = "";
init( _ value : String) {
name = value;
}
}

// with container, only "name" is to be visible
class abcContainer {
private var _abc : abc;
init( _ obj : abc) {
_abc = obj;
}
// + extra methods here
func getName() -> String {
return _abc.name
}
}


The point would be that the dictionary would return instances of
abcContainer
instead of just the plain raw
abc
class.

I wanted to use the sequence protocol to make the conversion automatic, but I was not able to transform the
[String:abc]
into
[String:abcContainer]
automatically like this:

// the iterator is implemented just iterating the inner basic dict
// but wrapping the result value as abcContainer
class abcIterator : Sequence, IteratorProtocol {

private var __source : [String:abc]?;
var index = 0
var myIterator : DictionaryIterator<String, abc>;

init(_ ctxArray: [String:abc]) {
self.__source = ctxArray
index = 0;
myIterator = (__source?.makeIterator())!
}

func next() -> abcContainer? {
let nextItem = myIterator.next();
if(nextItem != nil) {
return abcContainer((nextItem?.value)!);
}
return nil;
}
}

// this was supposed to be the wrapper over the collection
class abcCollection : Sequence {

private var __source : [String:abc]?;

init(_ list: [String:abc]) {
self.__source = list
}

func makeIterator() -> abcIterator {
return abcIterator(self.__source!);
}
}


I'm probably missing something very basic here. When I try to use the collection like this:

var dict : [String:abc] = [String:abc]();
dict["abba"] = abc("John Smith");

for (key,value) in abcCollection(dict) {
print(key, value.getName());
}


I get error: Expression type "abcCollection" is ambiguous without more context

Does anyone have idea how to make it work? What is missing? I have a feeling that this answer has the information I need...

Swift 2 to 3 Migration for Swift Sequence Protocol

Answer

The problem in your original code is that abcCollection(dict) returned a sequence of abcContainer objects, and those cannot be assigned to a (key, value) tuple.

You can achieve your goal with

class abcCollection : Sequence {

    private var __source : [String:abc]

    init(_ list: [String:abc]) {
        self.__source = list
    }

    public func makeIterator() -> AnyIterator<(AnyObject,abcContainer)> {
        let mapped = self.__source.lazy.map {
            ($0.key as AnyObject, abcContainer($0.value))
        }
        return AnyIterator(mapped.makeIterator())   
    }
}

Making __source non-optional makes all the (optional) unwrappings redundant, and lazy.map { ... } returns a lazily evaluated sequence of key/value pairs which is then type-erased.

Comments