Bit academic, but look at this code
// Some protocol
protocol R : Equatable
{
}
// Some class
class E : R
{
// Default implementation
static func == ( lhs : E, rhs : E ) -> Bool
{
print ( "Comparing E ===" )
return lhs === rhs
}
}
// Some class with a string
class F : E
{
let f : String
init ( f : String )
{
self.f = f
}
// Copare strings
static func == ( lhs : F, rhs : F ) -> Bool
{
print ( "Comparing F ==" )
return lhs.f == rhs.f
}
}
// Some generic container type
class G < T : R > : R
{
let g : T
init ( g : T )
{
self.g = g
}
// Compare
static func == ( lhs : G, rhs : G ) -> Bool
{
print ( "Comparing G ==" )
return lhs.g == rhs.g
}
}
let f1 = F ( f : "abc" )
let f2 = F ( f : "abc" )
print ( "f1 == f2 ? \( f1 == f2 ) (expect true)" )
let g1 = G < F > ( g : f1 )
let g2 = G < F > ( g : f2 )
print ( "g1 == g2 ? \( g1 == g2 ) (expect true)" )
This gives
Comparing F ==
f1 == f2 ? true (expect true)
Comparing G ==
Comparing E ===
g1 == g2 ? false (expect true)
The code defines some protocol and then a class E
that implements it and provides a generic comparator. Next comes F
which overrides this comparator to compare the string f
it houses. Finally some container class G
that houses something that implements the protocol.
So far so good. Now let us compare stuff. Comparing to instances of F
works as the correct comparator is used. However, comparing two container classes does not work and it seems Swift calls too shallow. It calls the generic implementation provided in E
in stead of the deeper one overridden in F
. If this was Objective-C it would make that deeper call, even if the lhs
and rhs
were different classes and then it would typically crash. Swift will not allow it, which is easy to see by creating another class that e.g. contains Int
in stead of String
but at the same time it is not using the correct comparator it seems.
EDIT
This makes it worse. The change below is that f1
, f2
and g1
and g2
are defined more generally as being (or containing) superclass types E
. Even though F
overrides the comparator it is not used in any of the comparisons.
let f1 : E = F ( f : "abc" )
let f2 : E = F ( f : "abc" )
print ( "f1 == f2 ? \( f1 == f2 ) (expect true)" )
let g1 = G < E > ( g : f1 )
let g2 = G < E > ( g : f2 )
print ( "g1 == g2 ? \( g1 == g2 ) (expect true)" )
I suspect this has something to do with operator overloading vs. function overriding ... but any light will be appreciated.
EDIT 2
Toyed a bit with some
thinking if I use it then maybe it could get this to work the way I want but some
is not allowed for a function argument at present.