Best workaround for the lack of generic protocols

Let's say I have a protocol "ValueProvider", which is just something that provides a value:


protocol ValueProvider
{
     typealias ValueType
     func valueInContext(context: ValueProviderContext) -> ValueType
}


I have various structs that implement this protocol, such as:


struct Constant<T>: ValueProvider
{
     var value: T
     init(value: T)
     {
          self.value = value
     }
     func value(context: ValueProviderContext) -> T
     {
          return value
     }
}


and many other such (generic) structs.



I have another struct, Thing, that has properties which are value provides of particular type. Ideally, I would like to express it like this:


struct Thing
{
     var position: ValueProvider<CGPoint>
     var name: ValueProvider<String>
     ...
}



Unfortunately I cannot do this, because ValueProvider is a protocol (which cannot be generic in current version of Swift), and ValueProvider<String> is illegal as a property type.


It looks to me I basically have two options:


(1) Make a new generic ThingProperty<T> enum, use that as the type of the "position" and "name" properties. The enum will have a value provider as its associated value. I don't like this solution because it forces me to change my model only because the type system cannot express what I want, although the runtime shouldn't have any problem with what I want. It feels like changing my model just to make the typechecker happy, which is absurd.


(2) Instead of "ValueProvider<CGPoint>", I can just use "ValueProvider" as the type of the position (and name) properties. This works and allows me to keep the model simple, but I loose the benefits of static typing to a large degree - the system doesn't know that the "position" and "model" properties can only hold CGPoint and String value providers, respectively. As a consequence, when I call valueInContext method on those properties, type checker wouldn't know the correct type of the return value.


What's the "correct" approach to take here? Am I missing something?

Accepted Reply

Mike, you do point out a really problematic shortcoming of Swift's current type system. I've written about it in an earlier thread with the title "Workarounds for lack of parameterized protocols?".


The folks from Apple working on the standard library were facing this problem all the time as well. They invented a design pattern as a workaround. I'll explain it using your example but using Apple's naming conventions.


Let's assume you want to define a protocol like ValueProviderType which abstracts over a type. You do this in Swift via an associated type:


protocol ValueProviderType {
  typealias Value
  func valueAtTime(time: Time) -> Value
}


This protocol isn't very useful as a type. You can basically only use it as a type constraint, but not standalone. This limitation can be worked around (with a hack) by defining a struct AnyValueProvider which wraps any implementation of ValueProviderType. This struct hides the concrete implementation of the value provider while providing a usable standalone type. Here's a way to implement AnyValueProvider:


struct AnyValueProvider<T>: ValueProviderType {
  let _valueAtTime: (Time) -> T
  init<V: ValueProviderType where V.Value == T>(_ delegatee: V) {
    _valueAtTime = delegatee.valueAtTime
  }
  func valueAtTime(time: Time) -> T {
    return _valueAtTime(time)
  }
}


I have not found a good general way to implement such wrappers, but the approach above using closures should be good enough in most cases (this is discussed in the thread "Workarounds for lack of parameterized protocols?").


Now with AnyValueProvider, you finally have a useful type which you have to use whenever you want to refer to a variable, a parameter, etc. of a concrete value provider. Here's an adaptation of your code:


typealias Time = Int
typealias Color = String
struct Car {
  var color: AnyValueProvider<Color>? = nil
  var position: AnyValueProvider<Double>? = nil
  init () {}
  func draw(time: Time) { }
}


Your existing value provider implementations don't need to be changed. They can stay:


struct ConstantValue<T>: ValueProviderType {
  var value: T
  init(_ value: T) {
    self.value = value
  }
  func valueAtTime(time: Time) -> T {
    return value
  }
}
struct TimeDependentValue<T>: ValueProviderType {
  var min: T
  var max: T
  init(_ min: T, _ max: T) {
    self.min = min
    self.max = max
  }
  func valueAtTime(time: Time) -> T {
    return min  // just for the example
  }
}


Whenever you need to create an instance of AnyValueProvider, you can simply pass your real value provider implementation to its constructor:


var carA = Car()
carA.position = AnyValueProvider(ConstantValue<Double>(123))
carA.color = AnyValueProvider(ConstantValue<Color>("red"))
var carB = Car()
carB.position = AnyValueProvider(TimeDependentValue<Double>(0, 123))
carB.color = AnyValueProvider(TimeDependentValue<Color>("red", "green"))


Does this explain how this pattern works? If you want more inspiration on how Apple uses this pattern, you can check out the various Any* classes provided by Apple in the standard library.


And if there's anyone who has a good idea how to implement those Any* wrappers, please let me know. I'm still very interested in this.

Replies

I tried playing with several approaches in a playground, and didn't come up with anything that works. You can certainly define a generic method in the ValueProvider protocol, but in the implementation, getting other struct members to share the generic type seemed insoluble ("can't convert value of type T to T").


One thing I didn't raise before is that if you have a typealias in the ValueProvider definition, you can (currently?) use the protocol only as a constraint, not as a type. This is going to get in your way anyway, generics aside.


It seems weird that you want value semantics for the value providers. Under what circumstances do you assign an existing (that is, not just explicitly created) value provider to another variable, where your intent is to make a copy? Other than that, how much do the semantics matter? Your use case seems like a gray area where neither value nor reference semantics does exactly what you want.


Finally, it's not clear at the moment whether Swift's current protocol conceptualization is intended to be mid-way between other language offerings, or is mid-course in a longer journey to something else. I wouldn't like to set my programming patterns in stone until I know the answer to that. Whatever the answer will be, for now all you can do is file your bug report showing your use cases, and live with what Swift allows, until it changes.

The important thing here is: Swift is NOT C++, C#, Java or Haskel - It is Swift, so solutions and patterns will be different.


Why are so many people trying to make Swift like other languages instead of using it as it is?

Your problem might be that value semantics, protocols and generics are not what you seem to think they are (judging by the way you use the terms and programming constructs). And this is not because Swift tries to put some dramatically different meaning into these notions compared to other languages, because it doesn't, not that different anyway.


First of all, there are "generic protocols" in Swift, it's just protocols with associated types. Just like your ValueProvider protocol.


So your problem is not the "lack of generic protocols" but rather this (error message): "Protocol 'ValueProvider' can only be used as a generic constraint because it has Self or associated type requirements"


If your ValueProvider protocol hadn't had its ValueType typealias, ie if it hadn't been generic, then, as you already know, position and color would have been possible to declare as ValueProviders (but that would not solve your problem in an elegant way).


Secondly, what you really are trying to achieve in your latest more concrete example scenario, if I understand you correctly, is that you want a bunch of cars that can change position and color in a way that should be controllable at runtime.


Probably you also want this to be implemented via your ValueProvider protocol, although I'm still not at all sure if this is a requirement or not, and I see nothing in the scenario that would make this the obvious way to structure the code. This is what I meant by self-contained scenario. There is nothing in your example scenario that lets us understand whether or why it is important or not to use eg ValueProviders and / or value semantics or any other implementation detail.

If someone here wrote a small and elegant Swift program that presented you with a bunch of cars that could move and change color, and their motion and color changing could be controlled at runtime. Would that be sufficient to solve your underlying problem? Even if the solution/program didn't include ValueProviders and didn't use (enough or any) value semantics?

And if you really do need value semantics, then I guess you will have to be a bit more specific as to eg why and in what parts of the scenario this is important. But it would of course be better to devise the scenario in such a way as to make such requirements implicit / self evident.

Mike, you do point out a really problematic shortcoming of Swift's current type system. I've written about it in an earlier thread with the title "Workarounds for lack of parameterized protocols?".


The folks from Apple working on the standard library were facing this problem all the time as well. They invented a design pattern as a workaround. I'll explain it using your example but using Apple's naming conventions.


Let's assume you want to define a protocol like ValueProviderType which abstracts over a type. You do this in Swift via an associated type:


protocol ValueProviderType {
  typealias Value
  func valueAtTime(time: Time) -> Value
}


This protocol isn't very useful as a type. You can basically only use it as a type constraint, but not standalone. This limitation can be worked around (with a hack) by defining a struct AnyValueProvider which wraps any implementation of ValueProviderType. This struct hides the concrete implementation of the value provider while providing a usable standalone type. Here's a way to implement AnyValueProvider:


struct AnyValueProvider<T>: ValueProviderType {
  let _valueAtTime: (Time) -> T
  init<V: ValueProviderType where V.Value == T>(_ delegatee: V) {
    _valueAtTime = delegatee.valueAtTime
  }
  func valueAtTime(time: Time) -> T {
    return _valueAtTime(time)
  }
}


I have not found a good general way to implement such wrappers, but the approach above using closures should be good enough in most cases (this is discussed in the thread "Workarounds for lack of parameterized protocols?").


Now with AnyValueProvider, you finally have a useful type which you have to use whenever you want to refer to a variable, a parameter, etc. of a concrete value provider. Here's an adaptation of your code:


typealias Time = Int
typealias Color = String
struct Car {
  var color: AnyValueProvider<Color>? = nil
  var position: AnyValueProvider<Double>? = nil
  init () {}
  func draw(time: Time) { }
}


Your existing value provider implementations don't need to be changed. They can stay:


struct ConstantValue<T>: ValueProviderType {
  var value: T
  init(_ value: T) {
    self.value = value
  }
  func valueAtTime(time: Time) -> T {
    return value
  }
}
struct TimeDependentValue<T>: ValueProviderType {
  var min: T
  var max: T
  init(_ min: T, _ max: T) {
    self.min = min
    self.max = max
  }
  func valueAtTime(time: Time) -> T {
    return min  // just for the example
  }
}


Whenever you need to create an instance of AnyValueProvider, you can simply pass your real value provider implementation to its constructor:


var carA = Car()
carA.position = AnyValueProvider(ConstantValue<Double>(123))
carA.color = AnyValueProvider(ConstantValue<Color>("red"))
var carB = Car()
carB.position = AnyValueProvider(TimeDependentValue<Double>(0, 123))
carB.color = AnyValueProvider(TimeDependentValue<Color>("red", "green"))


Does this explain how this pattern works? If you want more inspiration on how Apple uses this pattern, you can check out the various Any* classes provided by Apple in the standard library.


And if there's anyone who has a good idea how to implement those Any* wrappers, please let me know. I'm still very interested in this.

Thanks ObjectHub, finally an answer that sheds more light on this :-)

Jens, I'm not a beginner intentionally trying to find an obscure way to make cars move on screen :-)


The examples above are just extreme oversimplifications of what we're really doing.


We have a giant (hundreds of thousands lines of code) app written in Objective-C with a very complex model. We're doing a preliminary "research" in the direction of re-making the model in Swift, by making it immutable (or even better, use value semantics) for various reasons (concurrency, robust undo support, document history trees, etc.).


What I described above is semantically what we really need to do. You'll have to trust me on this; if I were to explain in detail why exactly is that what we need, I would need to write a book. It would be of no use to anybody.


With Objective-C, it is very inconvenient to make large, complex immutable models. The language wasn't really cut out to do that, so our current model is mutable. With Swift's value semantics, what we wanted to do for several years now can finally be done in relatively pain-free way.


If we do this with classes instead of structs and enums, we have no reason to use Swift at all - all the benefits we're looking for would vanish.

I don't think you're asking for anything 'magical' or 'against the Swift way', so some of the response you've gotten is somewhat unfortunate. I'm glad you got a serious answer though.


I think part of the issue is the problem framing. You're asking for protocol generics, but in the context of Swift, I think it would be more accurate to describe what you want as protocol type constraints. To paint a picture:


protocol<ValueProvider where ValueType == Double> // fully explicit
ValueProvider<ValueType=Double> // shorthand


So, basically, you want to create an anonymous protocol for all implementers of ValueProvider that meet an additional constraint on the associated type. To contrast this with what protocol generics might mean, consider:


struct ValueProviderType: ValueProvider<Int>, ValueProvider<String> { ... }


By having a type parameter, you make it so that for each possible argument to the type parameter you have a distinct protocol. You could then implement more than one of these resulting protocols for a given type. Rust is an example of a language that has both these features (constrained protocol types and generic protocols), and its trait (i.e. protocol) system can be fairly complicated as a result—which isn't necessarily a bad thing, but it's a definite tradeoff, especially since it makes the type system turing complete.


Java doesn't let you do what I suggested above with generic interfaces, of course, but Java basically uses interface type parameters as associated types. It just happens to require you to always constrain them to a specific type—even if that's another type parameter introduced solely for that purpose—and uses type parameter syntax to do this. This makes it essentially equivalent to what my "protocol type constraints" above would allow you to do in Swift.

Thank you Steve, your reply is much appreciated. I'm really happy that finally, some replies that understand the true nature of the problem/question are starting to appear. What you suggest as protocol type constraints would indeed perfectly solve my problem. So would generic protocols, as you outlined.


Is any of this planned for the future? Does anybody know a timeframe estimate? Is jonhull's suggestion the best temporary workaround?

Thank you very much. That seems like a usable workaround.

Having such a general mechanically applyable solution tells me that there is no underlying semantical problem with what MikeA, myself and others want to achieve but just a syntactical.

We would just need a syntax for describing anonymous protocols as SteveMcQwark describes in his answer below.

Resulting in (for example)

var color : ValueProviderType<where Value=Double> = MyValueProvider(5.0)

being "expanded" into

struct AnonymAnyValueProvider<T>: ValueProviderType { /* automatically generated delegation */ }
var color : AnonymAnyValueProvider<Double> = AnonymAnyValueProvider(MyValueProvider(5.0));


Since many people seem having trouble with this issue and as you say even the stdlib suffers from it, I am wondering why this is not what is done by swift.

I know this is an old thread … but i am interested in the latest thinking on this.