Swift Conditional Conformance with Any
You can create a generic method and remove the constraint from the extension:
extension Sequence {
func reduced<T>() -> Result<[T], Error> where Element == Result<T, Error> {
reduce(.success([])) {
switch $0 {
case .failure: return $0
case let .success(array):
switch $1 {
case let .failure(error): return .failure(error)
case let .success(value): return .success(array + CollectionOfOne(value))
}
}
}
}
}
Btw you can also use a plain loop and provide an early exit at the first failure:
extension Sequence {
func reduced<T>() -> Result<[T], Error> where Element == Result<T, Error> {
var array: [T] = []
for result in self {
switch result {
case let .failure(error): return .failure(error)
case let .success(value): array.append(value)
}
}
return .success(array)
}
}
A more concise approach would be to create a generic method that throws or return an array with all successes:
extension Sequence {
func successes<T, E>() throws -> [T] where Element == Result<T, E>, E: Error {
try map { try $0.get() }
}
}
Playground testing:
let z: [Result<Int, MyError>] = [.success(1),
.success(2),
.success(3)] //,
//.failure(.blah)]
do {
let successes = try z.successes()
print(successes) // [1, 2, 3]
} catch {
print(error)
}
Conditional Protocol Conformance to Protocol
The reason why this is not allowed is stated here:
This protocol extension would make any Collection of Equatable elements Equatable, which is a powerful feature that could be put to good use. Introducing conditional conformances for protocol extensions would exacerbate the problem of overlapping conformances, because it would be unreasonable to say that the existence of the above protocol extension means that no type that conforms to Collection could declare its own conformance to Equatable, conditional or otherwise.
See also this question.
If you just don't want to write the duplicate implementation of intRepr
everytime, you can do this:
struct StringContainer : ShowableAsIntContainer {
typealias T = String
let element: String
}
struct IntContainer : ShowableAsIntContainer {
typealias T = Int
let element: Int
}
extension Container where T : ShowableAsInt {
func intRepr() -> Int {
return element.intRepr()
}
}
typealias ShowableAsIntContainer = ShowableAsInt & Container
Why 'there cannot be more than one conformance, even with different conditional bounds'?
Is it impossible? Yes and no. It's not currently possible in Swift, as it has been implemented. It is in principle possible to be implemented.
The name for this is "overlapping conformances", and it was explicitly and purposely rejected. You can find the rationale in the "Alternatives considered" section of SE-0143 Conditional conformances. The TL;DR is: because it's really complicated.
Without knowing more about what exactly you were trying to use this for, there's not much direction we can provide.
Conditional Conformance: Using 'T' as a concrete type conformance to 'T' is not supported
Change the extension to Element is rather than Element conforms to
extension Array where Element == Social {
func speak() {
forEach { $0.speak() }
}
}
The constraint Array : Social
is irrelevant.
Conditional protocol conformance?
This was implemented in Swift 4.1.
Conditional Protocol Conformance: Cannot convert value of type 'Array_' to specified type '[UInt8]'
In order for Array<UInt8>
to be BinaryCodable
, its element type UInt8
must be BinaryCodable
, which it isn't. That protocol has
default implementations of its required methods, but conformance must
still be declared explicitly:
extension UInt8: BinaryCodable {}
Then your extension String
compiles,
and you can even get rid of the forced cast as! BinaryCodable
in the
encoding method (and using guard
allows to save one line):
extension String: BinaryCodable {
public func binaryEncode(to encoder: BinaryEncoder) throws {
try Array(self.utf8).binaryEncode(to: encoder)
}
public init(fromBinary decoder: BinaryDecoder) throws {
let utf8: [UInt8] = try Array(fromBinary: decoder)
guard let str = String(bytes: utf8, encoding: .utf8) else {
throw BinaryDecoder.Error.invalidUTF8(utf8)
}
self = str
}
}
How can I get conditional protocol conformance with a protocol's parent?
The question as posed, "How can I get conditional protocol conformance with a protocol's parent?" is meaningless, because a protocol always conforms with its parent; there is no "conditional" about it.
As for your actual code, the problem is the phrase A<Resource>
. Saying A<Resource>
is not a correct resolution of A's T. You need to resolve T as a class, struct, or enum — not as a protocol.
For example, if you have a class B that conforms to Resource, you can declare
let a = A<B>()
and all is well.
if there was a way to let
A<Resource>
know that it will always be working with concrete types that conform toCodable
Well, as I said, your code compiles fine as soon as A is working with a concrete type that does conform to Codable
. So if that's what A will always be working with, there's nothing more to do. You could of course tell A that its T will always conform to Resource (which by definition will always conform to Codable):
class A<T:Resource> {}
Swift Conditional conformances with Generic Type
A constraint on the extension can restrict the placeholder type E
to concrete types or protocols, for example:
extension Box where E: Item<Any> {}
extension Box where E == String {}
extension Box where E: Numeric {}
But you cannot put a generic constraint on the extension:
extension Box<A> where E: Item<A> {}
// Error: Constrained extension must be declared on the unspecialized generic
// type 'Box' with constraints specified by a 'where' clause
The solution is to restrict the method instead:
extension Box {
func mapOnItem<A, B>(function: (A) -> B) -> Box<Item<B>> where E: Item<A> {
return Box<Item<B>>(val: Item(val: function(self.value.value)))
}
}
Workaround for conditional conformance in Swift (was: Adding protocol to a constrained generic types)
An updated answer now that we have Swift 4.2, conditional conformance is now added as a feature.
From their spec on Github, this sort of code is now valid
extension List : Printable where T: SomeType {
func className() -> String {
return "List<SomeType>"
}
}
Related Topics
Parse.Com Pfquery Order by Time (Swift)
Error While Using Property 'Cgrectgetwidth', It Says It Was Replaced with 'Cgrect.Width'
Can't Change Uiimageview Image in Function (Swift)
Swift Optional Property Using Kvc Causes Crash
Binary Operator '==' Cannot Be Applied to Operands of Type 'Uilabel' and 'String'
Switch Control to Toggle Ishidden
Swift Optional Variable Assignment with Default Value (Double Question Marks)
Error: Couldn't Irgen Expression, No Additional Error
Uitextview Linktextattributes Font Attribute Not Applied to Nsattributedstring
What Does Cloning a Github Repository Mean
Apple Vision Framework - Text Extraction from Image
How to Correctly Initialize an Unsafepointer in Swift
How to Stop an Infinitely Rotating Image? and How Does One Implement Removeallanimations