Delegate Protocol w/ 'Associated Type Requirements'

Using a delegate pattern, I'd like to write the following:

protocol VariableDelegate {
  typealias Object
  func canAssign (variable: Variable<Object>, value:Object) -> Bool
}

class Variable<Object> {
  var value : Object
  var delegate : VariableDelegate<Object>?

  func assign (value: Object) {
   if (delegate?.canAssign(self, value: value) ?? true) {
     self.value = value
   }
}
}


But alas the `var delegate` declaration is flagged for 'associated type requirements'. What is a preferred approach to such a pattern?


I know I can write this as:

protocol VariableDelegate {
  typealias Object
  func canAssign (variable: Variable<Object,Self>, value:Object) -> Bool
}

class Variable<Object, Delegate:VariableDelegate where Delegate.Object == Object> {
  var value : Object
  var delegate : Delegate?

  // ...
}


but then I need to propagate the second type parameter as Variable<Object, SomeDelegate<Object>> which I am loath to do. I'm obviously not thinking about protocols and types properly. Can you help me with a mindset shift?

The easy approach is to avoid the delegate approach altogether.


class Variable<Object> {
 var value : Object
 var canAssign = { (value:Object) -> Bool in return true }

  func assign (value : Object) {
   if (canAssign(value)) {
     self.value = value
   }
 }
}


which isn't so bad but might not scale if the delegate actually has a broad interface. Time to dump delegates?

I can get a Protocol Oriented Programming approach mostly there:


public protocol VariableDelegate : class {
  typealias Value
  typealias Variable
  func canAssign (variable: Variable, value: Value) -> Bool
}

public protocol Variable {
  typealias Value = Self.Delegate.Value
  typealias Delegate : VariableDelegate
  var value : Value { get set }
  weak var delegate : Delegate? { get set }
  mutating func assign (value: Value)
}

extension Variable where Delegate.Value == Value, Delegate.Variable == Self {
  mutating func assign (value: Value) {
    if (delegate?.canAssign(self, value: value) ?? true) {
      self.value = value
    }
  }
}


but then I am left unable to construct a compileable BasicVariable (and still have two generic types for Value and Delegate):


public class BasicVariable<Object, Delegate:VariableDelegate where Delegate.Value == Object /, Delegate.Variable == Self */> : Variable {
  public var value : Object
  public weak var delegate : Delegate?

  init (value: Object) { self.value = value}
}

Can't express the type constraints correctly enough to satisfy the comiler.

As you already noticed, it is impossible to constrain a variable to a protocol that has self or associated type requirements – in your case it is the Object typealias in the VariableDelegate that causes this problem. What you need is a concrete intermediate type that conforms to your protocol and resolves the type requirements (you can still use generics, however). As an example, the following will work:


protocol VariableDelegateType {
    typealias Object
    func canAssign(variable: Variable<Object>, value: Object) -> Bool
}

class VariableDelegate<Object>: VariableDelegateType {
    func canAssign(variable: Variable<Object>, value: Object) -> Bool {
        // Your implementation...
        return true
    }
}

class Variable<Object> {
    var value: Object
    weak var delegate: VariableDelegate<Object>?

    init(value: Object) { self.value = value }

    func assign(value: Object) {
        if delegate?.canAssign(self, value: value) ?? true {
            self.value = value
        }
    }
}


To be honest, I don't know the scientific background of this restriction. In fact, if anyone knows why this is, please let me know too!


Edit: My suggestion probably won't solve your problem. I'm afraid there is currently no way to achieve what you want with Swift (at least not with the delegate pattern), but I'd love to be corrected if I'm wrong.

It's a little hard to tell without more context, but it seems like all you're really aiming for here is to ensure that the Variable and the prospective value are of the same object type. You can express that directly in the delegate protocol without naming the specific type:


protocol VariableDelegate {
    func canAssign<T>(variable: Variable<T>, value: T) -> Bool
}


Then the delegate protocol is free of typealiases and everything becomes much easier. And inside the implementation of canAssign(), you can reference T just as you would have referenced the Object typealias.

I appreciate this answer but I distilled my example code down to a minimal example. As with most delegate patterns, the protocol will have more than one function; if each function is parameterized with its own `T`, then one can't express that all the functions are expected to work on 'the one T'.

Delegate Protocol w/ 'Associated Type Requirements'
 
 
Q