Declare Trivial Protocol Conformance for Struct in a Framework

Why doesn't a class have to provide a failable initializer if it implements a protocol that declares one?

This is for the same reason that this compiles:

class A {
init?(s:String) {}
init() {}
}
class B : A {
override init(s:String) {super.init()}
}

init can override (i.e. be substituted for) init?.

See also the docs (when something is so clearly documented, it seems silly to ask "why"; it's just a fact about the language):

A failable initializer requirement can be satisfied by a failable or nonfailable initializer on a conforming type.

(As pointed out in the comments on the question and on the answer, this makes perfect sense if you think about the difference between an init? that happens never to fail and an init with the same signature — namely, there is no effective difference. To put it another way: You can tell me that I may fail, but you cannot tell me that I must fail.)

Swift 3.1: Crash when custom error is converted to NSError to access its domain property

While casting from Error to NSError it is trying to access the errorCode and errorDomain. Adding these extensions fixed my problem in the same case.

extension CustomError: LocalizedError {
public var errorDescription: String? {
return "Some localized description"
}
}

extension CustomError: CustomNSError {
public static var errorDomain: String {
return "Some Domain Name"
}
public var errorCode: Int {
return 204 //Should be your custom error code.
}
}

Why Swift Tuples can be compared only when the number of elements is less than or equal to 6?

Background: Tuples aren't Equatable

Swift's tuples aren't Equatable, and they actually can't be (for now). It's impossible to write something like:

extension (T1, T2): Equatable { // Invalid
// ...
}

This is because Swift's tuples are structural types: Their identity is derived from their structure. Your (Int, String) is the same as my (Int, String).

You can contrast this from nominal types, whose identity is solely based off their name (well, and the name of the module that defines them), and whose structure is irrelevant. An enum E1 { case a, b } is different from an enum E2 { case a, b }, despite being structurally equivalent.

In Swift, only nominal types can conform to protocols (like Equatble), which precludes tuples from being able to participate.

...but == operators exist

Despite this, == operators for comparing tuples are provided by the standard library. (But remember, since there is still no conformance to Equatable, you can't pass a tuple to a function where an Equatable type is expected, e.g. func f<T: Equatable>(input: T).)

One == operator has to be manually be defined for every tuple arity, like:

public func == <A: Equatable, B: Equatable,                                                       >(lhs: (A,B        ), rhs: (A,B        )) -> Bool { ... }
public func == <A: Equatable, B: Equatable, C: Equatable, >(lhs: (A,B,C ), rhs: (A,B,C )) -> Bool { ... }
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, >(lhs: (A,B,C,D ), rhs: (A,B,C,D )) -> Bool { ... }
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable, >(lhs: (A,B,C,D,E ), rhs: (A,B,C,D,E )) -> Bool { ... }
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable, F: Equatable>(lhs: (A,B,C,D,E,F), rhs: (A,B,C,D,E,F)) -> Bool { ... }

Of course, this would be really tedious to write-out by hand. Instead, it's written using GYB ("Generate your Boilerplate"), a light-weight Python templating tool. It allows the library authors to implement == using just:

% for arity in range(2,7):
% typeParams = [chr(ord("A") + i) for i in range(arity)]
% tupleT = "({})".format(",".join(typeParams))
% equatableTypeParams = ", ".join(["{}: Equatable".format(c) for c in typeParams])

// ...

@inlinable // trivial-implementation
public func == <${equatableTypeParams}>(lhs: ${tupleT}, rhs: ${tupleT}) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
${", ".join("lhs.{}".format(i) for i in range(1, arity))}
) == (
${", ".join("rhs.{}".format(i) for i in range(1, arity))}
)
}

Which then gets expanded out by GYB to:

@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable>(lhs: (A,B), rhs: (A,B)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1
) == (
rhs.1
)
}

@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable, C: Equatable>(lhs: (A,B,C), rhs: (A,B,C)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1, lhs.2
) == (
rhs.1, rhs.2
)
}

@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable>(lhs: (A,B,C,D), rhs: (A,B,C,D)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1, lhs.2, lhs.3
) == (
rhs.1, rhs.2, rhs.3
)
}

@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable>(lhs: (A,B,C,D,E), rhs: (A,B,C,D,E)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1, lhs.2, lhs.3, lhs.4
) == (
rhs.1, rhs.2, rhs.3, rhs.4
)
}

@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable, F: Equatable>(lhs: (A,B,C,D,E,F), rhs: (A,B,C,D,E,F)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1, lhs.2, lhs.3, lhs.4, lhs.5
) == (
rhs.1, rhs.2, rhs.3, rhs.4, rhs.5
)
}

Even though they automated this boilerplate and could theoretically change for arity in range(2,7): to for arity in range(2,999):, there is still a cost: All of these implementations have to be compiled and produce machine code that ends up bloating the standard library. Thus, there's still a need for a cutoff. The library authors chose 6, though I don't know how they settled on that number in particular.

Future

There's two ways this might improve in the future:

  1. There is a Swift Evolution pitch (not yet implemented, so there's no official proposal yet) to introduce Variadic generics, which explicitly mentions this as one of the motivating examples:

    Finally, tuples have always held a special place in the Swift language, but working with arbitrary tuples remains a challenge today. In particular, there is no way to extend tuples, and so clients like the Swift Standard Library must take a similarly boilerplate-heavy approach and define special overloads at each arity for the comparison operators. There, the Standard Library chooses to artificially limit its overload set to tuples of length between 2 and 7, with each additional overload placing ever more strain on the type checker. Of particular note: This proposal lays the ground work for non-nominal conformances, but syntax for such conformances are out of scope.

    This proposed language feature would allow one to write:

    public func == <T...>(lhs: T..., rhs: T...) where T: Equatable -> Bool { 
    for (l, r) in zip(lhs, rhs) {
    guard l == r else { return false }
    }
    return true
    }

    Which would be a general-purpose == operator that can handle tuples or any arity.

  2. There is also interest in potentially supporting non-nominal conformances, allowing structural types like Tuples to conform to protocols (like Equatable).

    That would allow one to something like:

    extension<T...> (T...): Equatable where T: Equatable {
    public static func == (lhs: Self, rhs: Self) -> Bool {
    for (l, r) in zip(lhs, rhs) {
    guard l == r else { return false }
    }
    return true
    }
    }


Related Topics



Leave a reply



Submit