Identifiable and implicitly unwrapped optional (IUO) ids

Hello,

One can't define an Identifiable type with a IUO id:

// Error: Type 'Player' does not conform to protocol 'Identifiable'
struct Player: Identifiable {
    var id: Int!
}

// Error: Type 'Player' does not conform to protocol 'Identifiable'
struct Player: Identifiable {
    typealias ID = Int?
    var id: Int!
}

This can be bothersome for some people.

This sounded like a fun game to me, so I tried to achieve it anyway (implement Identifiable conformance with an IUO id). What I came up with is:

struct Player: Identifiable {
    // Neat: IUO
    var id: Int!
    
    // Identifiable conformance
    typealias ID = Int?

    @_disfavoredOverload           // Avoid ambiguity between the two ids
    @_implements(Identifiable, id) // Tell Identifiable where to look at
    var optionalID: ID { id }
}

THIS IS NOT A RECOMMENDED TECHNIQUE, because of the use of two underscored compiler attributes that are not part of the public language interface.

This works in all situations I could check, with direct use of the identifiable type, and in generic contexts:

func printID<T: Identifiable>(_ t: T) {
    print(t.id)
}

var player = Player()

printID(player)      // prints "nil"
player.id = 12
print(player.id + 1) // prints "13"
printID(player)      // prints "Optional(12)"

I was unable to prevent the optionalID property from showing up in autocompletion, though.


I wonder what language lawyers think here:

  • Is support for IUO-backed optional associated types lacking in Identifiable, and other similar protocols? After all, since SE-0054, IUO are no longer a type: only their genuine optional facet can be used as an associated type. Should I open an issue?
  • If not (meaning that IUO support will never come ready made), is support for non-underscored workarounds desirable?

cc @Ben_Cohen (you were the review manager of SE-0261 - Identifiable Protocol).

3 Likes

It seems to be more universal issue...

protocol P {
  associatedtype T // WITHOUT ANY CONSTRAINTS
  var t: T { get }
}

struct S0: P {
  var t: Int // No error
}

struct S1: P {
  var t: Int? // No error
}

struct S2: P {
  var t: Int! // ⛔️ error: type 'S2' does not conform to protocol 'P'
}
1 Like

Yes, it is a universal issue. But not an abstract one without real consequence. It actually prevents IUO from doing their job: being convenient, when appropriate, as decided by the developer.

4 Likes