Home > Software design >  Swift Generics: Conforming to protocol by constraining generic parameters to variable types defined
Swift Generics: Conforming to protocol by constraining generic parameters to variable types defined

Time:02-20

In my Domain module I am defining a protocol Assignment, TimeLog and AssignmentTimeLog.

When defining a concrete implementation I want to use generics to conform to the AssignmentTimeLog protocol. To do so I am constraining my generic A, T parameters to be of type Domain.Assignment and Domain.TimeLog. Why does this not satisfy the protocol requirements? I want to understand the logic of what's going on.

// Domain Module
public protocol AssignmentTimeLog {

    var assignment: Assignment { get }
    var timeLog: TimeLog { get }
}

// My attempt to create an implementation trows an error
// Error: 
// Type 'AssignmentTimeLog<A, T>' does not conform to protocol 'AssignmentTimeLog'

import Domain

struct AssignmentTimeLog<A, T>: 
    Domain.AssignmentTimeLog where A: Domain.Assignment, T: Domain.TimeLog {
    
    var assignment: A
    var timeLog: T
 
}

For Context: The reason for using generics is that later I want to define an extension on AssignmentTimeLog where A & T also implement another protocol. This provides additional functionality without additional code. Concrete types implement the Domain protocols as well as those additional protocols.

I have tried to figure out this by reading the documentation and multiple blogs. But I can't seem to zone in on the exact issue/gap in understanding that I have.

CodePudding user response:

The protocol says a different thing from what your implementation says.

Fact 1

According to the protocol this getter

var assignment: Assignment { get }

can return any value conforming to Assignment.

Fact 2

On the other hand your implementation here

var assignment: A

says that assignment will contain a value of a specific type A (which happens to conform to Assignment).

These are 2 very different statements.

The fix

Here's an easy fix

protocol AssignmentTimeLog {
    
    associatedtype A: Assignment
    associatedtype B: TimeLog
    
    var assignment: A { get }
    var timeLog: B { get }
}


struct MyAssignmentTimeLog<A, T>: AssignmentTimeLog where A: Assignment, T: TimeLog {
    
    var assignment: A
    var timeLog: T
 
}
  • Related