2

Let's assume I've a protocol Foo with an associatedtype Bar. Is there any way to use this same associatedtype as a constraint in a generic function inside this same protocol?

To illustrate:

protocol Foo { associatedtype Bar func example<T: Bar>() -> T } 

This will throw a Inheritance from non-protocol, non-class type 'Self.Bar'. Which makes total sense, because at compile-time, we don't know which type Bar will be.

Nonetheless, for some reason, even if I define the Bar type, I will still get the same error. Something like this:

protocol Foo { associatedtype Bar: NSObject //OR: Protocol func example<T: Bar>() -> T //Compile Error: Inheritance from non-protocol, non-class type 'Self.Bar' } 

Both this and this questions address the same issue, but none of them are real answers in my honest opinion.

Also, maybe I'm approaching this in a wrong perspective of the language, but to visualize my use case: I need that when the class defines the type of Bar, each T used in example() function, should be a Bar type, but knowing which type it will return. To illustrate what would be my state of art:

protocol Foo { associatedtype Bar: NSObject //OR: Protocol //Compile Error: Inheritance from non-protocol, non-class type 'Self.Bar' func example<T: Bar>() -> T //OR: func example<T>() -> T where T: Bar } class ExampleBarType: NSObject { } class ExampleObject: ExampleBarType { } class FooImplementation: Foo { typealias Bar = ExampleBarType func example<T: Bar>() -> T { //OR: func example<T>() -> T where T: Bar { } } 

I just can't seem to grasp why the compiler can't assume that my associatedtype will be the one that I've defined. Thanks in advance.

0

3 Answers 3

1

What you're designing here isn't possible to implement. This isn't a Swift problem; I mean it's literally not possible to implement because the types don't make the promises you need. Consider this part:

class ExampleBarType {} // Not an NSObject subclass. class FooImplementation: Foo { typealias Bar = ExampleBarType func example<T: Bar>() -> T { // What would you write here? } } 

How do you plan to write that function body? Consider the following caller:

class MyBar: Bar { init(x: Int) {} } let ex: MyBar = foo.example() 

How would you implement example? How can you construct MyBar? You don't know the parameters for the init method (it requires an Int that you don't have). But your function signature claims that this function will return whatever specific subclass of Bar the caller requests.

In general you should avoid mixing protocols, generics, and subclassing in the same type system. They pull in different directions and it is very difficult to keep your system coherent. You're going to wind up with a lot of cases where you can't fulfill your promises.

You should go back to your concrete problem and need. If you're doing this "because I want to be as generic as possible," I recommend stopping. The Swift type system is very powerful, but also has some very tricky limitations, and "as generic as possible just because" almost always slams into those restrictions. If you have a concrete use case in a real program, however, you often (though not always) can avoid those headaches.

Sign up to request clarification or add additional context in comments.

Comments

0

I know it's an advanced topic. May this way can give you some lights.

protocol Foo { associatedtype Bar: NSObject //OR: Protocol func example() -> Bar //OR: } class ExampleBarType: NSObject { } class ExampleObject: ExampleBarType { } class FooImplementation: Foo { typealias Bar = ExampleBarType func example<T: Bar>() -> T { return Bar.init() as! T } } 

2 Comments

Yeah, this is currently the workaround I'm using, and it's exactly what I didn't wanted to do - to cast the return of my Type T -, but thanks for the tip.
What happens if I call let x: BarSubclass = foo.example()? I would expect that to crash. A Bar can't be as-cast to BarSubclass.
0

I'm not sure I'm fully understanding your use case but, isn't this enough for doing what you need to do?

protocol Foo { associatedtype Bar func example() -> Bar } protocol BarProtocol { } class BarOne: BarProtocol { } class BarTwo: BarProtocol { } class FooImplementationOne: Foo { func example() -> BarProtocol { return BarOne() } } class FooImplementationTwo: Foo { func example() -> BarProtocol { return BarTwo() } } 

1 Comment

Hey, thanks for answering. But no, this doesn't solve, mainly because I would always need to cast the return of example. Using your example for instance, the function FooImplementationOne example() function should return a BarOne instance, and FooImplementationTwo example() function should explicitly return a BarTwo instance. When you remove the generics from the example() function, it just knows that the type is BarProtocol meaning that I would've to cast everytime I wanted its type.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.