Protocol with protocol variable


(Lorenzo) #1

Hi there,

I hope this is the best place for this question.
Today I came across something in the design of the Swift language that baffled me, and I can't find a design explanation for why this works the way it does.

Let's suppose I have the following code:

protocol Pet { }

protocol Human {
  var pet: Pet { get }
}

struct Cat: Pet { }

// This does not compile: 
// type 'Italian' does not conform to protocol 'Human'
struct Italian: Human {
  var pet: Cat 
}

Why isn't this possible? Whatever a human with a pet can do, an Italian with a cat can do as well, and this is ensured by the fact that Italian conforms to Human and Cat conforms to Pet.

What am I missing here?

Thanks,
Lorenzo

P.S. I know already about alternative solutions, I'm just wondering why this language design decision has been taken.


(Suyash Srijan) #2

Unfortunately, covariance isn't allowed in that context right now. You can do:

protocol Pet { }

protocol Human {
	associatedtype P where P: Pet
	var pet: P { get }
}

struct Cat: Pet { }

// Works
struct Italian: Human {
	var pet: Cat
}

to work around the above problem.


(Jordan Rose) #3

This is SR-522. I think the main reason it's not implemented is because it would be more work, not because anyone thinks it's not a good idea. However, changing that behavior now could break source compatibility, since there might be a default implementation of a requirement that wasn't being considered and now is.


(Slava Pestov) #4

It is also not clear how covariance would work with associated type inference.


(Ladislas de Toldi) #5

I ran into the same "issue" myself a few days ago. Thanks @suyashsrijan for the workaround!


#6

I’m curios why covariance should be allowed here? The Human protocol requires a var that can store any Pet, but the Italian struct defines a var that can only store Cats. It seems to me the compiler is correct that the protocol is not satisfied. What if you had a function accepting a Human existential which tried to assign a Bird as the pet, and you passed an instance of Italian?

Edit: never mind, just noticed it’s {get} only. Sorry for the noise.