With Xcode 8.2.1 and Swift 3, if I show the protocol definition for the Error
protocol I see this in the generated header:
public protocol Error { }
extension Error { }
// at line 1250:
public func <<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func ><T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func <=<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func >=<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
My question is about the operators that appear immediately under the extension Error { }
:
These operators appear to say that default implementations exist for types that have a RawValue
subtype that is Comparable
.
So I wrote some code in a playground to see if I could use these operators. Here's the first attempt:
struct S<RawValue> {
let v: RawValue
}
let s = S<Int>(v: 0)
let t = S<Int>(v: 1)
s < t // error: Binary operator '<' cannot be applied to two 'S<Int>' operands
In the S
struct above, we have a RawValue
subtype, and when instantiated as shown in variables s
and t
as Int
the RawValue
is comparable. Yet <
fails.
Here is attempt #2:
enum E: RawRepresentable {
case value(Int)
init(rawValue: Int) {
self = .value(rawValue)
}
var rawValue: Int {
switch self {
case .value(let rawValue):
return rawValue
}
}
}
let e = E.init(rawValue: 0)
let f = E.init(rawValue: 1)
e < f // error: Binary operator '<' cannot be applied to two 'E' operands
Again, we have a RawValue
type that is Comparable
, but no joy.
So I guess I'm missing something fundamental here. The Swift "Misc" header tells me that Comparable
methods exist for T where T.RawValue: Comparable
, but when I try to compare these sorts of T
s it doesn't work.
Any ideas?
Interesting. In Swift 3.1, those overloads show up in the generated header as:
public func <<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func ><T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func <=<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func >=<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
which makes a lot more sense, as without constraining T
, there's no knowing that it has a RawValue
. So it just looks like a visual error in the pre-Swift 3.1 generated header.
_SwiftNewtypeWrapper
is a protocol, which according to its header, is:
/// An implementation detail used to implement support importing /// (Objective-)C entities marked with the swift_newtype Clang /// attribute. public protocol _SwiftNewtypeWrapper : RawRepresentable { }
Therefore the overloads you see are used in order to define comparison operations on types that are bridged to Swift by being marked with the swift_newtype
Clang attribute (for more info on this attribute, see this article), where their RawValue
is Comparable
.
For example, the following:
#import <Foundation/Foundation.h>
typedef NSString* _Nonnull Foo __attribute__((swift_newtype(enum)));
static const Foo FooBar = @"bar";
static const Foo FooBaz = @"baz";
static const Foo FooQux = @"qux";
gets bridged to Swift as:
public struct Foo : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable {
public init(rawValue: String)
public static let bar: Foo
public static let baz: Foo
public static let qux: Foo
}
and you are able to use the various comparison operators with instances of Foo
:
func lessThan<T : _SwiftNewtypeWrapper>(lhs: T, rhs: T) -> Bool where T.RawValue : Comparable {
return lhs < rhs
}
let b = Foo.bar
print(lessThan(lhs: b, rhs: b))
(although there appears to be some rough edges around this, for example attempting to use them directly yields an 'ambiguous use of' compiler error)
However, for 'pure Swift' code, the overloads you've found should bare no relevance. Swift types that conform to RawRepresentable
with Comparable
RawValue
s don't automatically get <
overloads or Comparable
conformance – you have to implement that yourself.