Add constraints to typealiases inside Swift protocols - swift

How can I indicate that B.Generator.Element should be A?
protocol SomeProtocol {
typealias A
typealias B: CollectionType
func f(a: A) -> B
}
I realise that I can do func f(node: B.Generator.Element) -> B and eliminate A altogether, but I can't do this if A is defined in some other protocol and SomeProtocol inherits from it.
Edit:
Added example
protocol P {
typealias A
}
protocol Q: P {
typealias B: CollectionType
typealias A = B.Generator.Element
func f(node: A) -> B
}
func g<A, T: Q where A == T.A>(arg1: T, arg2: A) {
let collection = arg1.f(arg2)
collection.contains(arg2) // Error here
}
Edit 2:
To clarify, I am looking to somehow specify A == B.Generator.Element in the protocol itself since I must use a free function. I found a thread in the developer forums with precisely my problem. Looks like its a limitation in the current type system. I've filed a radar, let's hope it gets resolved :)
Edit 3:
A radar already exists for the issue. Use rdar://21420236 while filing.

How about:
protocol SomeProtocol {
typealias A = B.Generator.Element
typealias B: CollectionType
func f(a: A) -> B
}
Edit:
The error you're getting is because there's no guarantee A (B.Generator.Element) conforms to Equatable. Therefore you can't call contains on collection since contains is defined as:
extension SequenceType where Generator.Element : Equatable {
public func contains(element: Self.Generator.Element) -> Bool
}
(I'm not sure why Xcode is presenting contains as a valid method to call, could be a bug...)
To solve this you can do:
// Since you're using Swift 2 you could use a protocol extension instead of a free function.
// Unfortunately, Xcode complains without the explicit declaration that `A` is
// `B.Generator.Element`.
extension Q where A: Equatable, A == B.Generator.Element {
func g(elem: A) {
let collection = f(elem)
collection.contains(elem)
...
}
}

Related

Difference between protocol combining typealias and empty conforming protocol

Is there a difference between these two in Swift?
protocol ABProtocol: AProtocol, BProtocol {}
typealias ABProtocol = AProtocol&BProtocol
To make things clearer, I will rename the second one to:
typealias ABProtocolIntersection = AProtocol & BProtocol
I can think of two differences off the top of my head.
If your type conform to AProtocol and BProtocol, the type is automatically a subtype of ABProtocolIntersection, but it does not automatically conform to ABProtocol. After all, ABProtocol is a totally different protocol.
Example:
class Foo: AProtocol, BProtocol { ... }
func foo<T: ABProtocolIntersection>(type: T.Type) { }
func bar<T: ABProtocol>(type: T.Type) { }
foo(type: Foo.self) // works
bar(type: Foo.self) // error
Another difference is that you can put extensions on ABProtocol, but not ABProtocolIntersection:
extension ABProtocol { } // OK
extension ABProtocolExtension { } // error
This is because ABProtocolIntersection is a non-nominal type, similar to types like (Int, Int) or (Int) -> String. See also: What is a 'non-nominal type' in Swift?
Yes there is a difference. The former defines a new protocol to which types must conform when it is used. The latter only defines a "placeholder" for AProtocol&BProtocol
Consider the following code:
protocol AProtocol{}
protocol BProtocol{}
protocol ABProtocol1: AProtocol, BProtocol {}
typealias ABProtocol2 = AProtocol & BProtocol
func f1(value: ABProtocol1) {}
func f2(value: ABProtocol2) {}
Arguments to f1 must conform to ABProtocol1 but arguments to f2 can conform to AProtocol and BProtocol. You do not need to explicitly conform types to ABProtocol2. For example:
struct A: AProtocol, BProtocol
{
}
f1(value: A()) // Error!
f2(value: A()) // OK

Protocol associatedType and <>

what is a difference between using generic with function or using associatedType in swift protocols?
protocol Repository {
associatedtype T
func add(data : T) -> Bool
}
and
protocol Repository {
func add<T>(data : T) -> Bool
}
Defined associated type makes classes which conform protocol strong typed. This provide compile-time error handling.
In other hand, generic type makes classes which conform protocol more flexible.
For example:
protocol AssociatedRepository {
associatedtype T
func add(data : T) -> Bool
}
protocol GenericRepository {
func add<T>(data : T) -> Bool
}
class A: GenericRepository {
func add<T>(data : T) -> Bool {
return true
}
}
class B: AssociatedRepository {
typealias T = UIViewController
func add(data : T) -> Bool {
return true
}
}
class A could put any class into add(data:) function, so you need to makes your sure that function handle all cases.
A().add(data: UIView())
A().add(data: UIViewController())
both would be valid
But for class B you will get compile-time error when you will try to put anything except UIViewController
B().add(data: UIView()) // compile-time error here
B().add(data: UIViewController())
An associatedtype is a static type in struct/class which adopts the protocol either via a typealias declaration or via type inference. The type is always the same for that class.
A generic can be anything, even different types in the same class.
This case
protocol Repository {
func add<T>(data : T) -> Bool
}
Is understood by compiler like: "Any type that is fed to the func add will be acceptable and the result of the function will be Bool"
But this
protocol Repository {
associatedtype T
func add(data : T) -> Bool
}
is understood by compiler like: "func add will accept only the type that is defined in the typealias T = ... and return Bool"
In the second case you restrict generic parameters only to the typealiased types.
Another important feature shows up when you use generic parameters in multiple functions of the protocol. In that case it guarantees that func add<T> and func multiply<T> will have the same type T. In case of generic functions it is not guaranteed.
protocol Calculable {
associatedtype T
func add<T>(a: T, b: T) -> T
func multiply<T>(a: T, b: T) -> T
}
// In this case you know that T is the same for all functions
protocol CalculableDifferent {
func add<T>(a: T, b: T) -> T
func multiply<T>(a: T, b: T) -> T
}
// In this case add can accept One type, when multiply can accept Another

Can not conform to protocol by creating extension with Where Clauses

protocol Typographable {
func setTypography(_ typography: Typography)
}
extension UILabel: Typographable {}
extension Typographable where Self == UILabel {
func setTypography(_ typography: Typography) {
self.font = typography.font
self.textColor = typography.textColor
self.textAlignment = typography.textAlignment
self.numberOfLines = typography.numberOfLines
}
}
I have create a protocol Typographable, the UILabel implement this protocol, and the implementation is in the extension Typographable where Self == UILabel.
it works perfectly in swift 4.0, but it not works any more in swift 4.1, the error message is Type 'UILabel' does not conform to protocol 'Typographable'
I have read carefully the CHANGELOG of swift 4.1, but I can't find anything useful.
Is this normal, did I miss something ?
This is pretty interesting. Long story short (okay maybe not that short) – it's an intentional side effect of #12174, which allows for protocol extension methods that return Self to satisfy protocol requirements for non-final classes, meaning that you can now say this in 4.1:
protocol P {
init()
static func f() -> Self
}
extension P {
static func f() -> Self {
return self.init()
}
}
class C : P {
required init() {}
}
In Swift 4.0.3, you would get a confusing error on the extension implementation of f() saying:
Method 'f()' in non-final class 'C' must return Self to conform to protocol 'P'
How does this apply to your example? Well, consider this somewhat similar example:
class C {}
class D : C {}
protocol P {
func copy() -> Self
}
extension P where Self == C {
func copy() -> C {
return C()
}
}
extension C : P {}
let d: P = D()
print(d.copy()) // C (assuming we could actually compile it)
If Swift allowed the protocol extension's implementation of copy() to satisfy the requirement, we'd construct C instances even when called on a D instance, breaking the protocol contract. Therefore Swift 4.1 makes the conformance illegal (in order to make the conformance in the first example legal), and it does this whether or not there are Self returns in play.
What we actually want to express with the extension is that Self must be, or inherit from C, which forces us to consider the case when a subclass is using the conformance.
In your example, that would look like this:
protocol Typographable {
func setTypography(_ typography: Typography)
}
extension UILabel: Typographable {}
extension Typographable where Self : UILabel {
func setTypography(_ typography: Typography) {
self.font = typography.font
self.textColor = typography.textColor
self.textAlignment = typography.textAlignment
self.numberOfLines = typography.numberOfLines
}
}
which, as Martin says, compiles just fine in Swift 4.1. Although as Martin also says, this can be re-written in a much more straightforward manner:
protocol Typographable {
func setTypography(_ typography: Typography)
}
extension UILabel : Typographable {
func setTypography(_ typography: Typography) {
self.font = typography.font
self.textColor = typography.textColor
self.textAlignment = typography.textAlignment
self.numberOfLines = typography.numberOfLines
}
}
In slightly more technical detail, what #12174 does is allow the propagation of the implicit Self parameter through witness (conforming implementation) thunks. It does this by adding a generic placeholder to that thunk constrained to the conforming class.
So for a conformance like this:
class C {}
protocol P {
func foo()
}
extension P {
func foo() {}
}
extension C : P {}
In Swift 4.0.3, C's protocol witness table (I have a little ramble on PWTs here that might be useful in understanding them) contains an entry to a thunk that has the signature:
(C) -> Void
(note that in the ramble I link to, I skip over the detail of there being thunks and just say the PWT contains an entry to the implementation used to satisfy the requirement. The semantics are, for the most part, the same though)
However in Swift 4.1, the thunk's signature now looks like this:
<Self : C>(Self) -> Void
Why? Because this allows us to propagate type information for Self, allowing us to preserve the dynamic type of the instance to construct in the first example (and so make it legal).
Now, for an extension that looks like this:
extension P where Self == C {
func foo() {}
}
there's a mismatch with the signature of the extension implementation, (C) -> Void, and the signature of the thunk, <Self : C>(Self) -> Void. So the compiler rejects the conformance (arguably this is too stringent as Self is a subtype of C and we could apply contravariance here, but it's the current behaviour).
If however, we have the extension:
extension P where Self : C {
func foo() {}
}
everything's fine again, as both signatures are now <Self : C>(Self) -> Void.
One interesting thing to note about #12174 though is that is preserves the old thunk signatures when the requirements contain associated types. So this works:
class C {}
protocol P {
associatedtype T
func foo() -> T
}
extension P where Self == C {
func foo() {} // T is inferred to be Void for C.
}
extension C : P {}
But you probably shouldn't resort to such horrific workarounds. Just change the protocol extension constraint to where Self : C.

How should I write this in Swift?

Let's say that I create a protocol like this:
protocol A {
associatedtype T
func computeSomething(with:T) -> Double
}
In my generic typed class, I would like to do something like this:
class B<U> {
var doSomething:A<U>
}
This thing is that this generates an error, but I would like to accept any type that would support computeSomething on my type U but I don't know at all how to do that?
Edit for clarity
Basically if A was a generic struct or class, that would be possible, but what if no default implementation (provided by class or struct) makes sense here and the only thing I want is to ensure that the type does what I want?
Edit #2 (with concrete example)
I wanted to simplify my question which makes it pretty hard to understand so here is a still simplified and fictional problem that probably matches better the issue I am encountering:
I am writing a generic class that processes its generic type T:
class Process<T> { ... }
The class Process itself includes code that processes T, but in order for this code to work, it needs T to conform to some protocols, for instance:
protocol A {
func mixWith(other:A) -> A
}
protocol B {
var isFoo:Bool { get set }
}
So my first approach was to simply require T to conform to those protocols:
class Process<T:<A,B>> { ... }
This looks like the simplest approach and probably is in many cases, but in my case I think that this actually is problematic, for this reason:
First, I may need to process the same type in many different ways, and changing a way a type is being processed often requires changing the actual implementation of protocols A and B for instance in this case, fooProcess and barProcess are both of type Process with generic type MyType:
let fooProcess = Process<MyType>()
let barProcess = Process<MyType>()
But I want fooProcess and barProcess to do different operations which in many cases would require to change the implementation of the A and B protocols of my MyType type and that's simply not possible.
So my first idea was to simply require some closures and variables to be defined so that I wouldn't need protocols anymore and would define the way data is being processed only in my Process class, a little bit like this:
class Process<T> {
//
var mix:(_ lhs:T, _ rhs:T)->(T)
var isFoo:(_ a:T)->(Bool)
...
}
There all of the processing would be directly implemented in my Processing class, again this would have looked like the right solution but now comes another issue, which led me to my associated type approach: it turns out that in many cases, the user of my Process class would want to get some default behaviour implemented by my framework, for instance, I could automatically implement protocol A and B for them as long as their class conformed to protocol X, here is how it did it:
protocol X:A,B {
...
}
extension protocol X {
// Here was my default implementation of A and B, which enabled my user to directly get A and B implemented as long as their type conformed to X
}
By using this method, I would let my user directly choose what they wanted to implement themselves, by conforming to protocol X they would only need to write a little bit of code and let my framework to all of the rest by itself, and if they wanted to implement themselves A or B they still could.
So if I am right, there is no way to do such a thing with my closures implementation.
So for this reason, I thought that an associated type protocol would be a good solution because here I could let my users easily get some default behaviour or write their own, so now we are getting back to my original question:
protocol AProcessing {
associatedtype U
func mix(_ lhs:U, _ rhs:U) -> U
}
protocol BProcessing {
associatedtype U
func isFoo(_ a:U) -> Bool
}
And then do something like that:
class Process<T> {
var aProcessor:AProcessing<T>
var bProcessor:BProcessing<T>
}
Here the advantage compared to closures is that I could write a special class conforming to AProcessing that could provide default implementation, this way:
class AutomaticAProcessing<T:X>:AProcessing { ... }
That would have enabled my users to so something like that:
var processData = Process<SomeType>()
processData.aProcessor = AutomaticAProcessing<SomeType>()
processData.bProcessor = TheirOwnImplemtation
Not only is this not possible in Swift, but it also feels like I am using too many "hacks" to get things done and there should be an easier language feature to do that, unfortunately I don't know what I should use.
I don't think it is possible, because the generic type of the protocol is specified in the class that implements it.
You could write something like this:
class B<U, P: A> where P.T == U {
var someVar: P?
}
But then you would need to specify a second parameter with the specific class. For example:
class C: A {
typealias T = String
func computeSomething(with: String) -> Double {
return 0.0
}
}
let b = B<String, C>()
let c = b.someVar
But it can't return a protocol with specific type in its associatedtype
One way would be to start with an empty generic struct, and then extend it on types where it makes sense:
struct A<T> {}
extension A where T: Base {
func computeSomething(with: T) -> Double {
return 1
}
}
Usage:
protocol Base {}
class B<U: Base> {
let doSomething = A<U>()
func foo(x: U) -> Double {
return doSomething.computeSomething(with: x)
}
}
class Z : Base {}
let x = B<Z>()
let y = x.foo(x: Z())
print(y)
To EDIT #2:
Remove associated types, and it should be workable:
protocol A {}
protocol B {}
protocol AProcessing {
func mix(_ lhs: A, _ rhs: A) -> A
}
protocol BProcessing {
func isFoo(_ a: B) -> Bool
}
Then, your processor:
class Process<T: A & B> {
var aProcessor: AProcessing!
var bProcessor: BProcessing!
func foo(_ a: T) -> Bool {
let x = aProcessor.mix(a, a)
guard let b = x as? B else { return false }
return bProcessor.isFoo(b)
}
}
And usage:
struct AutomaticAProcessing : AProcessing {
func mix(_ lhs: A, _ rhs: A) -> A { return lhs }
}
struct TheirOwnImplemtation : BProcessing {
func isFoo(_ a: B) -> Bool { return false }
}
struct SomeType : A, B {}
var processData = Process<SomeType>()
processData.aProcessor = AutomaticAProcessing()
processData.bProcessor = TheirOwnImplemtation()
let x = SomeType()
let y = processData.foo(x)
print(y)

protocol with same associated type name

If I have two protocols whose associated type happens to be the same, such as
protocol Read {
associatedtype Element
func read() -> Element
}
protocol Write {
associatedtype Element
func write(a: Element)
}
Then I would like to have a class to read integer from and write string to:
class ReadWrite: Read, Write {
func read() -> Int {
return 5
}
func write(a: String) {
print("writing \(a)")
}
}
but the compiler complains and suggests changing String to Int. Ideally the type should be inferred, or at least compiles if I explicitly declare
associatedtype Read.Element = Int
associatedtype Write.Element = String
within ReadWrite. Any work around?
update
Workaround inspired by this question is to create two auxiliary protocols
protocol ReadInt: Read {
associatedtype Element = Int
}
protocol WriteString: Write {
associatedtype Element = String
}
and have the class inherit from these two instead:
class ReadWrite: ReadInt, WriteString {
func read() -> Int {
return 5
}
func write(a: String) {
print("writing \(a)")
}
}
This seems to compile, but I am afraid of any gotcha following this way.
update again
I found the issue in Swift's issue tracker. Anyone require this missing feature (like me) should vote for it. As a comparison, this pattern is possible in Rust, which also supports associated types (although this is not an idiomatic usage).
Another workaround is to create a third, combined protocol:
protocol ReadWrite {
associatedtype R
associatedtype W
func read() -> R
func write(a: W)
}
It's not pretty, since it forces you to redeclare the protocol members, but it does keep it generic (you're not limited to String and Int).