0

Can anyone explain why this doesn't compile?

// In MyViewKit.framework

protocol UserRenderable {
    var name : String { get }
}

protocol PostRenderable {
    var title: String { get }
    var author: UserRenderable { get }
}

// In MyDataKit.framework

struct User {
    let id: String
    let name : String
}

struct Post {
    let id: String
    let title: String
    let author: User
}

// In MyApp

extension User : UserRenderable {}

extension Post: PostRenderable {}

But this (below) does? Apparently, read-only property requirements in a protocol can't be satisfied by a property which conforms to them (according to the answers to this question.)

What is typealias doing here?

// In MyViewKit.framework

protocol UserRenderable {
    var name : String { get }
}

protocol PostRenderable {
    var title: String { get }
    var author: UserRenderable { get }
}

// In MyDataKit.framework

struct User {
    let id: String
    let name : String
}

struct Post {
    let id: String
    let title: String
    let author: User
}

// In MyApp    

extension User : UserRenderable {}

extension Post: PostRenderable {
    // what is type alias doing here? Note: there are no associated types.
    typealias User = UserRenderable
}

UPDATE Just clarifying why IMO this isn't a duplicate to Why can't a get-only property requirement in a protocol be satisfied by a property which conforms?. I understand the limitation in the Swift language: I'm trying to also understanding whether or not this is a valid workaround.

Sam Ballantyne
  • 487
  • 6
  • 18
  • 1
    The second example works because the `author` property is of typed as `UserRenderable`, which is what the protocol requires. The `typealias` just (very confusingly) locally redefines `User` to be `UserRenderable`, nothing more. – Hamish Feb 05 '18 at 13:13
  • 1
    “What is typealias doing here?” just what it always does. It is making User mean UserRenderable, thus satisfying the PostRenderable requirement. This throws away completely the old meaning of User, of course. It is not your User struct any more, it’s just a way of spelling UserRebderable, within Post. – matt Feb 05 '18 at 13:14
  • If your goal is to have PostRenderable require that `author` be a UserRenderable adopter, make it a generic. – matt Feb 05 '18 at 13:19
  • @matt I'm trying to understand THIS workaround, not one using generics. Doing anything using associated types would mean that PostRenderable wasn't usable anywhere as a type. – Sam Ballantyne Feb 05 '18 at 13:23
  • It’s NOT a workaround. Your question adds nothing to the duplicate, it just muddies the waters. – matt Feb 05 '18 at 13:23
  • It's a significant difference. Please unmark this question as a duplicate. – Sam Ballantyne Feb 05 '18 at 13:23
  • The workaround question has been completely answered, in two comments. You were just confusing yourself. Now you’re not. – matt Feb 05 '18 at 13:24
  • @Hamish, re: "The typealias just (very confusingly) locally redefines User to be UserRenderable, nothing more" can this be used to fudge protocol conformance, in the way I'm looking for, or no? What are the weakness of this? – Sam Ballantyne Feb 05 '18 at 13:27
  • @SamBallantyne As matt says, no, this doesn't achieve anything over just typing the `author` property as `UserRenderable`. Though that being said, do you even need protocols here to begin with? What other types would conform to `UserRenderable` & `PostRenderable`? – Hamish Feb 05 '18 at 13:28
  • @Hamish I added some doc comments to clarify the use case – Sam Ballantyne Feb 05 '18 at 13:32

1 Answers1

0

A typealias has nothing to do with associated types in this particular instance. Typealias is just a way to let the compiler know what is the associated type in a protocol if it cannot be inferred, but a typealias can be used in different contexts as well.

Your second example compiles, because you change User from a concrete type to a typealias for UserRenderable in your Post extension. If you check the type of author in Xcode, you'll see that its type is actually UserRenderable after the extension rather than User. Due to the typealias, inside Post, User won't refer to the User struct, but rather it will be UserRenderable due to the local overwrite you did with the typealias.

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116