I have a class with a property which should have as type what in other languages would be called a generic (or template) interface. When I try to mimic this behavior in Swift I cannot get protocols to work with the idea. For example:
protocol P {
typealias T
func returnT() -> T
}
class G<T>: P {
var t: T
init(t: T) {
self.t = t
}
func returnT() -> T {
return t
}
}
class C {
var p: P<Int> // Cannot specialize non-generic type 'P'
init(instanceOfP: P<Int>) { // Cannot specialize non-generic type 'P'
p = instanceOfP
}
func usePsT() -> Int {
return p.returnT() // 'P' does not have a member named 'returnT'
}
}
Errors from the compiler are reported as comments. It seems clear to me that such a situation should not be problematic: but since Swift's protocols cannot be generics (they use this obscure typealias syntax instead) C has no way to know that every class that implements P can be specialized for Int. Is there a Swift-y way to represent this situation correctly? Or is there any known workaround so that I don't have to force or de-generalize the class structure?
The generic isn't really needed in your protocol (use Any) - it's needed in your class G<T>. You could do this...
protocol P {
func returnT() -> Any
}
class G<T>: P {
var t: T
init(t: T) {
self.t = t
}
func returnT() -> Any {
return t
}
}
class C {
var p: P
init(instanceOfP: P) {
p = instanceOfP
}
func usePsT() -> Any {
return p.returnT()
}
}
let gi = G<Int>(t: 7) // {t 7}
let ci = C(instanceOfP: gi) // {{t 7}}
ci.usePsT() // 7
let gs = G<String>(t: "Hello")
let cs = C(instanceOfP: gs)
cs.usePsT() // "Hello"
My solution is not ideal but saves me a lot of complications, still code is readable...
Instead of interfaces I use base class with open empty functions.
Like this:
public class CSTableControllerFilter<Row: CSTableControllerRow, Data> {
open func filter(data: [Row]) -> [Row] { data }
open func onReloadDone(in controller: CSTableController<Row, Data>) {}
}
Related
Assume I have this bit of code:
protocol MyProtocol {
}
struct MyStruct: MyProtocol {
}
class MyClass<P: MyProtocol> {
// Required for compiling
required init() {
}
}
class MySpecialClass: MyClass<MyStruct> {
}
func foo<P: MyProtocol, C: MyClass<P>>(protocolType: P.Type) -> C {
return C()
}
This compiles and calling
let specialClass: MySpecialClass = foo(protocolType: MyStruct.self)
creates an instance of type MySpecialClass.
What I would like is to not have to pass in the type of P so that I could simply call
let specialClass: MySpecialClass = foo()
and P would be automatically deduced.
Is there any way to make this happen?
As #Hamish already mentioned,
func foo<P, C: MyClass<P>>() -> C {
return C()
}
let specialClass: MySpecialClass = foo()
works in Swift 4. The Swift 3 compiler however complains that
error: generic parameter 'P' is not used in function signature
and a possible workaround is to add a dummy parameter of type
P? with a default value:
func foo<P, C: MyClass<P>>(dummy: P? = nil) -> C {
return C()
}
let specialClass: MySpecialClass = foo()
I believe that this will work:
protocol MyProtocol {
}
struct MyStruct: MyProtocol {
}
class MyClass<P: MyProtocol> {
// added a typealias for P
typealias ContainedProtocol = P
// Required for compiling
required init() {
}
}
class MySpecialClass: MyClass<MyStruct> {
}
// added a default value for protocolType
func foo<P, C: MyClass<P>>(protocolType: P.Type = C.ContainedProtocol.self) -> C {
return C()
}
let specialClass: MySpecialClass = foo()
By adding a typealias for P in MyClass<P: MyProtocol> we can refer to that type. We then set it as a default value in foo<P, C: MyClass<P>>(protocolType:) -> C. The compiler can then deduce P from that information.
Martin R’s version seems to work about as well as mine so go with whichever you like best. His seems a bit cleaner as it doesn’t need a typealias and it is fairly succinct.
Here’s his (it was a comment, it’s now an answer):
func foo<P, C: MyClass<P>>(dummy: P? = nil) -> C { ... }
From an external library I've got the following scenario.
The protocol and base class:
protocol P1 {
// P1 Stuff
}
class A {
// A Stuff
}
Then there is an extension, which causes my troubles. It is defined for the combination of types P1 and A.
extension P1 where Self : A {
public func myDesiredFunc() {
// Do stuff.
}
}
And finally there are the implementations B1 - Bn, which I use.
class B1 : A, P1 {
}
class B2 : A, P1 {
}
...
In my code I need to put together instances of B-classes and work with them. The problem is, that I need to use the extension func myDesiredFunc(). So I need somehow define, that the array type is something like [(A & P1)] and the return type of producing funciton is (A & P1) as well.
However, with this code:
func createBeeInstance() -> (A & P1) {
if something {
return B1()
} else if something {
return B2()
}
...
}
I'm getting the error:
Non-protocol type 'A' cannot be used within a protocol composition.
Is there a way to say that the return type is a composition of class and protocol? I'm not able to change the scenario because it's an external library.
Swift 4:
^_^
it's possible now to compose class and protocol in swift 4 so modifying the previous snippets to this should work
class A {
// A Stuff
required init () {}
}
protocol P1 {
// P1 Stuff
}
class B1 : A {}
class B3: P1 {}
class B2 : A, P1 {}
func createBeeInstance<T: P1 & A>(type: T.Type) -> T {
return type.init()
}
var things = [P1 & A]() // still Element has to be P1 as well
let f = createBeeInstance(type: B2.self)
//let f1 = createBeeInstance(type: B1.self) // will error
//let f2 = createBeeInstance(type: B3.self) // will error
things.append(f) // is fine
--- OLD Way which did not work ---
You may use this way ,
having the Sample you provided with modifying class A to have init
class A {
// A Stuff
required init () {}
}
modifying createBee method to
func createBeeInstance<T: P1>(type: T.Type) -> T where T: A {
return type.init()
}
this way you will provide the type as an input e.g. B1.self
for array we can provide typealieased generic
typealias B<T:P1> = T where T: A
var things = [B<A>]() // still Element has to be P1 as well
let f = createBeeInstance(type: B2.self)
let f1 = createBeeInstance(type: B1.self)
things.append(f)
One possible solution would be to define a protocol that defines the essential nature of objects of type A (let's call the new protocol Aable), and make the A type conform to it:
class A: Aable {
// A stuff
}
You could then constrain the P1 protocol extension with Aable instead of A:
extension P1 where Self : Aable {
func myDesiredFunc() {
// Do stuff.
}
}
That would allow you to use protocol composition for the return type of a function...
func createBeeInstance(useB1: Bool) -> (Aable & P1) {
return useB1 ? B1() : B2()
}
...as well as for the element type of an array:
var things = [Aable & P1]()
for i in 1...5 {
let b = createBeeInstance(useB1: i % 2 == 0)
things.append(b)
}
for thing in things {
thing.myDesiredFunc()
}
I have a protocol P that returns a copy of the object:
protocol P {
func copy() -> Self
}
and a class C that implements P:
class C : P {
func copy() -> Self {
return C()
}
}
However, whether I put the return value as Self I get the following error:
Cannot convert return expression of type 'C' to return type 'Self'
I also tried returning C.
class C : P {
func copy() -> C {
return C()
}
}
That resulted in the following error:
Method 'copy()' in non-final class 'C' must return Self to conform
to protocol 'P'
Nothing works except for the case where I prefix class C with final ie do:
final class C : P {
func copy() -> C {
return C()
}
}
However if I want to subclass C then nothing would work. Is there any way around this?
The problem is that you're making a promise that the compiler can't prove you'll keep.
So you created this promise: Calling copy() will return its own type, fully initialized.
But then you implemented copy() this way:
func copy() -> Self {
return C()
}
Now I'm a subclass that doesn't override copy(). And I return a C, not a fully-initialized Self (which I promised). So that's no good. How about:
func copy() -> Self {
return Self()
}
Well, that won't compile, but even if it did, it'd be no good. The subclass may have no trivial constructor, so D() might not even be legal. (Though see below.)
OK, well how about:
func copy() -> C {
return C()
}
Yes, but that doesn't return Self. It returns C. You're still not keeping your promise.
"But ObjC can do it!" Well, sort of. Mostly because it doesn't care if you keep your promise the way Swift does. If you fail to implement copyWithZone: in the subclass, you may fail to fully initialize your object. The compiler won't even warn you that you've done that.
"But most everything in ObjC can be translated to Swift, and ObjC has NSCopying." Yes it does, and here's how it's defined:
func copy() -> AnyObject!
So you can do the same (there's no reason for the ! here):
protocol Copyable {
func copy() -> AnyObject
}
That says "I'm not promising anything about what you get back." You could also say:
protocol Copyable {
func copy() -> Copyable
}
That's a promise you can make.
But we can think about C++ for a little while and remember that there's a promise we can make. We can promise that we and all our subclasses will implement specific kinds of initializers, and Swift will enforce that (and so can prove we're telling the truth):
protocol Copyable {
init(copy: Self)
}
class C : Copyable {
required init(copy: C) {
// Perform your copying here.
}
}
And that is how you should perform copies.
We can take this one step further, but it uses dynamicType, and I haven't tested it extensively to make sure that is always what we want, but it should be correct:
protocol Copyable {
func copy() -> Self
init(copy: Self)
}
class C : Copyable {
func copy() -> Self {
return self.dynamicType(copy: self)
}
required init(copy: C) {
// Perform your copying here.
}
}
Here we promise that there is an initializer that performs copies for us, and then we can at runtime determine which one to call, giving us the method syntax you were looking for.
With Swift 2, we can use protocol extensions for this.
protocol Copyable {
init(copy:Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(copy: self)
}
}
There is another way to do what you want that involves taking advantage of Swift's associated type. Here's a simple example:
public protocol Creatable {
associatedtype ObjectType = Self
static func create() -> ObjectType
}
class MyClass {
// Your class stuff here
}
extension MyClass: Creatable {
// Define the protocol function to return class type
static func create() -> MyClass {
// Create an instance of your class however you want
return MyClass()
}
}
let obj = MyClass.create()
Actually, there is a trick that allows to easily return Self when required by a protocol (gist):
/// Cast the argument to the infered function return type.
func autocast<T>(some: Any) -> T? {
return some as? T
}
protocol Foo {
static func foo() -> Self
}
class Vehicle: Foo {
class func foo() -> Self {
return autocast(Vehicle())!
}
}
class Tractor: Vehicle {
override class func foo() -> Self {
return autocast(Tractor())!
}
}
func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
let vehicle = Vehicle.foo()
let tractor = Tractor.foo()
print(typeName(vehicle)) // Vehicle
print(typeName(tractor)) // Tractor
Swift 5.1 now allow a forced cast to Self, as! Self
1> protocol P {
2. func id() -> Self
3. }
9> class D : P {
10. func id() -> Self {
11. return D()
12. }
13. }
error: repl.swift:11:16: error: cannot convert return expression of type 'D' to return type 'Self'
return D()
^~~
as! Self
9> class D : P {
10. func id() -> Self {
11. return D() as! Self
12. }
13. } //works
Following on Rob's suggestion, this could be made more generic with associated types. I've changed the example a bit to demonstrate the benefits of the approach.
protocol Copyable: NSCopying {
associatedtype Prototype
init(copy: Prototype)
init(deepCopy: Prototype)
}
class C : Copyable {
typealias Prototype = C // <-- requires adding this line to classes
required init(copy: Prototype) {
// Perform your copying here.
}
required init(deepCopy: Prototype) {
// Perform your deep copying here.
}
#objc func copyWithZone(zone: NSZone) -> AnyObject {
return Prototype(copy: self)
}
}
I had a similar problem and came up with something that may be useful so I though i'd share it for future reference because this is one of the first places I found when searching for a solution.
As stated above, the problem is the ambiguity of the return type for the copy() function. This can be illustrated very clearly by separating the copy() -> C and copy() -> P functions:
So, assuming you define the protocol and class as follows:
protocol P
{
func copy() -> P
}
class C:P
{
func doCopy() -> C { return C() }
func copy() -> C { return doCopy() }
func copy() -> P { return doCopy() }
}
This compiles and produces the expected results when the type of the return value is explicit. Any time the compiler has to decide what the return type should be (on its own), it will find the situation ambiguous and fail for all concrete classes that implement the P protocol.
For example:
var aC:C = C() // aC is of type C
var aP:P = aC // aP is of type P (contains an instance of C)
var bC:C // this to test assignment to a C type variable
var bP:P // " " " P " "
bC = aC.copy() // OK copy()->C is used
bP = aC.copy() // Ambiguous.
// compiler could use either functions
bP = (aC as P).copy() // but this resolves the ambiguity.
bC = aP.copy() // Fails, obvious type incompatibility
bP = aP.copy() // OK copy()->P is used
In conclusion, this would work in situations where you're either, not using the base class's copy() function or you always have explicit type context.
I found that using the same function name as the concrete class made for unwieldy code everywhere, so I ended up using a different name for the protocol's copy() function.
The end result is more like:
protocol P
{
func copyAsP() -> P
}
class C:P
{
func copy() -> C
{
// there usually is a lot more code around here...
return C()
}
func copyAsP() -> P { return copy() }
}
Of course my context and functions are completely different but in spirit of the question, I tried to stay as close to the example given as possible.
Just throwing my hat into the ring here. We needed a protocol that returned an optional of the type the protocol was applied on. We also wanted the override to explicitly return the type, not just Self.
The trick is rather than using 'Self' as the return type, you instead define an associated type which you set equal to Self, then use that associated type.
Here's the old way, using Self...
protocol Mappable{
static func map() -> Self?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> Self? {
...
}
}
Here's the new way using the associated type. Note the return type is explicit now, not 'Self'.
protocol Mappable{
associatedtype ExplicitSelf = Self
static func map() -> ExplicitSelf?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> SomeSpecificClass? {
...
}
}
To add to the answers with the associatedtype way, I suggest to move the creating of the instance to a default implementation of the protocol extension. In that way the conforming classes won't have to implement it, thus sparing us from code duplication:
protocol Initializable {
init()
}
protocol Creatable: Initializable {
associatedtype Object: Initializable = Self
static func newInstance() -> Object
}
extension Creatable {
static func newInstance() -> Object {
return Object()
}
}
class MyClass: Creatable {
required init() {}
}
class MyOtherClass: Creatable {
required init() {}
}
// Any class (struct, etc.) conforming to Creatable
// can create new instances without having to implement newInstance()
let instance1 = MyClass.newInstance()
let instance2 = MyOtherClass.newInstance()
When implementing a static protocol function returning Self in a protocol extension, an error appears at the implementation of the function in the extension (minimal simplified scenario shown without context):
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self { // Method 'f()' in non-final class 'NSData' must return `Self` to conform to protocol 'P'
return g()
}
}
extension NSData: P {
static func g() -> Self {
return self.init()
}
}
Replacing Self with P on the line the error occurs causes the compiler to segfault (sig 11) (which seems a valid way of conveying a type mismatch error).
Changing the declaration of f() to return P, as well as replacing Self with P on the error line, results in successful compilation, however loses type precision (and requires force downcasting at each call site, plus documenting the Self requirement in detail).
Are there any other workarounds for this issue that do not lose the generic return type?
EDIT: Further details to compensate for lack of context: P is a public protocol that will be exposed by a library, for various types to conform to (and override g()), so overriding f() in NSData is not an option. It is also preferable to not have to change f() to something other than a protocol extension, as it is used by the library internally in a number of places. Given these two options, changing the return type of f() to P is a better alternative.
Update
As of Swift 4 (possibly 3), the above code works as-is.
In Swift 3 or 4:
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self {
return g()
}
}
extension Data: P {
static func g() -> Data {
return self.init()
}
}
Or you can replace your class with a final subclass:
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self {
return g()
}
}
import Foundation
final class MyData: NSData {}
extension MyData: P {
static func g() -> Self {
return self.init()
}
}
If NSData is one of those class clusters that can't easily be subclassed (you'll see a stacktrace with __CFRequireConcreteImplementation), you may have to create a final class wrapper for a real NSData instead of using a subclass.
You'll need to override f() in your NSData extension.
The basic problem is (I think) that the compiler doesn't know what Self is when it compiles f in the protocol extension and I think it assumes it must be the exact type of the class it is applying it too. With NSData, that might not be the case because you might have a subclass of it.
this works for me ....
protocol P {
static func foo()->Self
}
class C {
required init() {}
}
extension C: P {
static func foo() -> Self {
return self.init()
}
}
let c = C()
let c2 = C.foo()
print(c.dynamicType, c2.dynamicType) // C C
ok, i see you note, so i made an update
protocol P {
static func foo()->Self
static func bar()->Self
}
extension P {
static func foo() -> Self { // Method 'f()' in non-final class 'NSData' must return `Self` to conform to protocol 'P'
return bar()
}
}
// the class C must be final ...
final class C {
}
// otherwise the compiler can not decide the type of Self in
extension C: P {
static func bar() -> Self {
return self.init()
}
}
let c = C()
let c2 = C.foo()
print(c.dynamicType, c2.dynamicType) // C C
with NSData, if you would like to make the same, the trouble is to declare NSData as final.
As of Swift 2.1, I was able to avoid the given error by only having structs (or 'final' classes) conform to the protocol. Currently, you can restrict protocol implementation to reference-types ("classes-only"), but I have not seen a similar restriction for value-types.
In this particular case though, I'd say a delegate pattern would suit. If appropriate, you could move a default implementation of f into a protocol extension, and have subclass implementations override a delegate property.
protocol P {
static var delegate : (() -> Self)?;
}
extension P {
static func f() -> Self {
// Use delegate if available, or use default implementation
}
}
extension NSData : P {
static var delegate : (() -> NSData)? = subImplementation;
func subImplementation() -> NSData {
// Some NSData-specific implementation
}
}
You can also get around it by using an associated type.
protocol P {
associatedtype Entity
static func f() -> Entity
static func g() -> Entity
}
extension P {
static func f() -> Entity {
return g()
}
}
extension Data: P {
static func g() -> Data {
return self.init()
}
}
You don't need to specify the Entity in your implementation as the compiler will infer it from your return type.
I've got the same problem, did you figure it out?
Here is another way I came out to deal with particular situation.
Instead of using protocol which required a static function returning Self, maybe you can consider defining a Initializer-required protocol.
Like this:
protocol SomeProtocol {
init(someParameter: Int)
}
Dont forget to mark the initializer implementation with the required keyword.
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
}
}
Hope this could help.
Consider the following:
protocol Foo {
typealias A
func hello() -> A
}
protocol FooBar: Foo {
func hi() -> A
}
extension FooBar {
func hello() -> A {
return hi()
}
}
class FooBarClass: FooBar {
typealias A = String
func hi() -> String {
return "hello world"
}
}
This code compiles. But if I comment out explicit definition of associated type typealias A = String, then for some reason, swiftc fails to infer the type.
I'm sensing this has to do with two protocols sharing the same associated type but without a direct assertion through, for example, type parameterization (maybe associated type is not powerful/mature enough?), which makes it ambiguous for type inference.
I'm not sure if this is a bug / immaturity of the language, or maybe, I'm missing some nuances in protocol extension which rightfully lead to this behaviour.
Can someone shed some light on this?
look at this example
protocol Foo {
typealias A
func hello() -> A
}
protocol FooBar: Foo {
typealias B
func hi() -> B
}
extension FooBar {
func hello() -> B {
return hi()
}
}
class FooBarClass: FooBar {
//typealias A = String
func hi() -> String {
return "hello world"
}
}
with generics
class FooBarClass<T>: FooBar {
var t: T?
func hi() -> T? {
return t
}
}
let fbc: FooBarClass<Int> = FooBarClass()
fbc.t = 10
fbc.hello() // 10
fbc.hi() // 10
Providing explicit values for associated types in a protocol is required for conformance to said protocol. This can be accomplished by hard coding a type, as you've done with typealias A = String, or using a parameterized type as you mentioned, such as below:
class FooBarClass<T>: FooBar {
typealias A = T
...
}
Swift will not infer your associated type from an implemented method of the protocol, as there could be ambiguity with multiple methods with mismatching types. This is why the typealias must be explicitly resolved in your implementing class.