Defining the method to be equivalent to a.dict == b.dict would be confusing IMHO, since you would expect it to also work when dicts are not equal. The definition should be more involved: when dicts are not equal, it should check whether all keys are equal. I’m not sure this can be done efficiently, since the order is not defined, but isempty(symdiff(a, b)) would work.
If you call collect, then the order matters (so if two dictionaries had the same keys but stored internally in a different order, the keys would not be seen to be equal, while IMO opinion you usually ask this question when you just care that haskey returns the same for both collections, and not about the order)
I suspect it’s faster to compare the lengths of the dictionaries rather than testing set membership in both directions. I’d propose something like this:
Base.:(==)(a::Base.KeyIterator, b::Base.KeyIterator) = length(a)==length(b) && all(k->in(k,b), a)
However, note that Dict is just one type of Associative and sometimes the question will be asked is: do two Associatives of different types have the same set of keys? Not sure that keys(a) == keys(b) could ever cover all cases if some Associatives just store their keys as a vector or a tuple, say.
One solution would be to make all the different KeyIterator objects subtypes of AbstractSet and make sure that they all have length, in, etc. Then it would be possible to define a general method for ==(a::AbstractSet, b::AbstractSet), if that does not exist already.
(It might be necessary to write faster methods for special cases to get reasonable performance, but that’s a separate issue.)
This makes sense to me. Why wouldn’t keys(dict) be an AbstractSet? It implements the entire (immutable) Set interface in a reasonable complexity. Sets are basically implemented as a view over the keys of a dictionary anyway.