Protocol with property of type Self can only be used as generic constraint, why?

Binarian

It is not possible to use a protocol with a property with Self as type as a type, container type, parameter. I think I need an example where it makes sense, that the compiler can not infer the type.

Definitions which compile

internal protocol Lovable {
    var inLoveTo: Self? {
        get
    }
}

internal final class Human: Lovable {
    var inLoveTo: Human? = nil
}

internal final class Animal: Lovable {
    var inLoveTo: Animal? = nil
}

internal let thing11: Human = Human()
internal let thing12: Animal = Animal()

Not working code

But the following code makes sense to me and could work. So there have to be a case where you can not infer the type at compile time, which I can not see yet.

import Darwin

let thing13: Lovable = Darwin.random() % 2 == 0 ? thing11 : thing12 // So you do not know which dynamicType thing13 has at compile time, but it should be Lovable, error: mismatching types

thing13.inLoveTo // It could be Lovable

// Does not work, even though it makes sense for me, since inLoveTo adopts Lovable
internal func partner(one: Lovable) -> Lovable {
    return one.inLoveTo
}

What do I not see?

Working example where at compile time you do not know the type

protocol Foo {
}

final class Bar1: Foo {
    let bla: Int8 = 100
}

final class Bar2: Foo {
    let bla: Int64 = 600000
}

internal let thing21: Foo = Bar1()
internal let thing22: Foo = Bar2()
internal let thing23: Foo = Darwin.random() % 2 == 0 ? thing21 : thing22 // So you do not know which type it has at compile time
Hamish

Self refers to the runtime type of whatever is implementing that protocol. The problem is that when you have a function that takes a Lovable input (or a variable with an explicit annotation of Lovable), you're upcasting to the abstract type Lovable.

By doing this you're losing the type information for what Self was. Was it an Animal or a Human? This is needed by the compiler in order to use the protocol as a type, as it has a property of type Self, which cannot be resolved. This therefore means you cannot use a protocol with Self or associatedtype requirements as an actual type, you can only ever use it as a generic constraint.

One potential solution is to change the property in your protocol to be of type Lovable. Now you're saying that everything that conforms to Lovable has a property of 'some other' Lovable. You now don't need to know the concrete type of whatever that 'something' is, although this will break an important relationship that you want to establish (two partners must be of the same type!)

One way to maintain this relationship (at least for your function) is to use generics. The reason why using generics works is they act as a placeholder for a concrete type, which is supplied to the function when you call it. Now your function input knows what Self is – it's whatever concrete type is supplied to the function.

You could make your partner function generic like so:

func partner<T:Lovable>(one: T) -> T? {
    return one.inLoveTo
}

This also guarantees that the return type of the function is of the same concrete type as the input (albeit wrapped in an optional), providing better type safety.

Unfortunately for your variable assignment, there's no real solution that doesn't involve breaking the relationship you've established (inLoveTo must be the same type as the class). You're trying to tie a runtime decision (Human or Animal could be assigned) to a static concrete type that's given at compile time, which cannot work.


As you've noted, using Self as a return type of a function doesn't make the protocol generic. I believe this is due to variance – as you can always pass a subclass to something that expects its superclass. Therefore as the return type of the function will match the current static type of your instance, the static type can only ever refer to a less specific type than the dynamic type of the instance. Therefore you can freely return an instance with the same dynamic type, as the static type that describes it can only be less type specific.

This behaviour is different with properties as the protocol has limited control over how they are implemented. {get} can be implemented as any kind of property, {get set} can be implemented as a stored or calculated property with a setter. In both of these cases, the property is potentially able to be set in the conforming class. Now we run into the original problem. Self is the concrete type of the class, therefore we have to know that concrete type in order to assign to it, which you lose upon upcasting.

You cannot simply treat the property as being a Loveable as that would allow any conforming instance to be assigned to it, i.e assigning an Animal() to a Human property – which is illegal.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Protocol with property of type Self can only be used as generic constraint, why?

From Dev

Why can this protocol "only be used as a generic constraint"?

From Dev

Why do I get the error “Protocol … can only be used as a generic constraint because it has Self or associated type requirements”?

From Java

What does "Protocol ... can only be used as a generic constraint because it has Self or associated type requirements" mean?

From Dev

Why can my simple protocol only be used as a generic constraint?

From Java

Protocol can only be used as a generic constraint because it has Self or associatedType requirements

From Dev

Swift Protocols with Typealises. Protocol can only be used as a generic constraint

From Dev

Why can't a protocol not be used as a type for a generic type in swift?

From Dev

Using self as a Generic Type Constraint

From Dev

Why can't I use a Guid as a generic type constraint?

From Dev

Constraint on generic type cannot be used in IEnumerable?

From Dev

Generic type constraint for numerical type only

From Dev

Swift generic type that conform to protocol cannot be used to refer protocol?

From Dev

Why do classes need to be "final" when adopting a protocol with a property with type "Self"?

From Dev

Swift type does not conform to protocol error at generic constraint but not at class itself

From Dev

Swift type does not conform to protocol error at generic constraint but not at class itself

From Dev

Generic type that can be used with the "+" operator

From Dev

Generic type in generic constraint

From Dev

Generic type in generic constraint

From Dev

Self referencing generic type constraint and XAML in UWP application

From Dev

Constraint: Two type variables can be used with an operator

From Dev

Downcast Generic AnyObject to Protocol Associated Type Self.Model

From Dev

Extending a Protocol where Self: Generic Type in Swift (Requires Arguments In <...>)

From Dev

Extending a Protocol where Self: Generic Type in Swift (Requires Arguments In <...>)

From Dev

Incorrectly Inferred Type in Generic Closure with Protocol Extension Constrained by Self

From Dev

Why is generic type information lost in generic functions with a Comparable constraint?

From Dev

Why is generic type information lost in generic functions with a Comparable constraint?

From Dev

Apple Swift: Generic type constraint for String type only not works

From Dev

Why property can be contain only setter in interface type in C#?

Related Related

  1. 1

    Protocol with property of type Self can only be used as generic constraint, why?

  2. 2

    Why can this protocol "only be used as a generic constraint"?

  3. 3

    Why do I get the error “Protocol … can only be used as a generic constraint because it has Self or associated type requirements”?

  4. 4

    What does "Protocol ... can only be used as a generic constraint because it has Self or associated type requirements" mean?

  5. 5

    Why can my simple protocol only be used as a generic constraint?

  6. 6

    Protocol can only be used as a generic constraint because it has Self or associatedType requirements

  7. 7

    Swift Protocols with Typealises. Protocol can only be used as a generic constraint

  8. 8

    Why can't a protocol not be used as a type for a generic type in swift?

  9. 9

    Using self as a Generic Type Constraint

  10. 10

    Why can't I use a Guid as a generic type constraint?

  11. 11

    Constraint on generic type cannot be used in IEnumerable?

  12. 12

    Generic type constraint for numerical type only

  13. 13

    Swift generic type that conform to protocol cannot be used to refer protocol?

  14. 14

    Why do classes need to be "final" when adopting a protocol with a property with type "Self"?

  15. 15

    Swift type does not conform to protocol error at generic constraint but not at class itself

  16. 16

    Swift type does not conform to protocol error at generic constraint but not at class itself

  17. 17

    Generic type that can be used with the "+" operator

  18. 18

    Generic type in generic constraint

  19. 19

    Generic type in generic constraint

  20. 20

    Self referencing generic type constraint and XAML in UWP application

  21. 21

    Constraint: Two type variables can be used with an operator

  22. 22

    Downcast Generic AnyObject to Protocol Associated Type Self.Model

  23. 23

    Extending a Protocol where Self: Generic Type in Swift (Requires Arguments In <...>)

  24. 24

    Extending a Protocol where Self: Generic Type in Swift (Requires Arguments In <...>)

  25. 25

    Incorrectly Inferred Type in Generic Closure with Protocol Extension Constrained by Self

  26. 26

    Why is generic type information lost in generic functions with a Comparable constraint?

  27. 27

    Why is generic type information lost in generic functions with a Comparable constraint?

  28. 28

    Apple Swift: Generic type constraint for String type only not works

  29. 29

    Why property can be contain only setter in interface type in C#?

HotTag

Archive