Question about heterogeneous collections


(Jason Sadler) #1

Hi folks,

I have an issue with using a heterogeneous array of objects conforming to a
protocol - I want to write an extension on Array (or CollectionType) that
applies only when Element : MyProtocol, but I can’t call methods in that
extension from an instance of [MyProtocol] because "Using ‘MyProtocol' as a
concrete type conforming to protocol ‘MyProtocol' is not supported”

(For more background, my full use case can be seen in this gist:
https://gist.github.com/sadlerjw/2cc16b4375b02fe7f400)

I’ve asked about this on swift-users (
https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160321/001560.html)
and got some good workarounds but no one was able to provide me with
information on any future plans in swift to address this issue - whether
that’s making protocols conform to themselves, or some other improved
approach to heterogeneous collections. I wonder if anyone here can shed
some light on this? (I’m new to the mailing lists, sorry!)

Thanks
Jason


(Haravikk) #2

Protocols aren’t like parent-classes, they can’t be used interchangeably as different struct implementations of MyProtocol may have radically different memory footprints. I think you can define a protocol for classes only which may allow you to use MyProtocol as a concrete type, but personally I don’t like the idea of limiting a protocol in that way; the correct way to store elements of MyProtocol is to define a type-erased wrapper AnyMyType that takes any instance of MyProtocol and hides it.

Type-erased wrappers are bit of a pain in the ass to define; in fact, in the discussion you linked someone recommended a method using closures to do it, but while this is a neat way to do it, it’s very inefficient in terms of memory (if you have four or five methods in your protocol then suddenly the wrapper will be adding hundreds of bytes of overhead). The correct way to implement these is outlined in the following guide:

https://realm.io/news/type-erased-wrappers-in-swift/

This is a horrible process with a ton of boiler-plate though, so there’s certainly an argument to be made for features that can reduce or eliminate the need for this. In fact, it’d be great if protocols had type-erased wrappers generated automatically, as this could avoid the somewhat unintuitive cases like the one you’ve run into, but then it would end up hiding the complexity of what’s actually happening.

For example, if you want to save a bunch of different MyProtocol variations in a collection, then you might consider declaring them as classes with a common ancestor instead, then use that ancestor as your array type, as this is one of the advantage of classes over structs (even though I generally prefer the latter in most cases). Type-erased wrappers also add overhead that you should be aware of, but typically a lot less (if you use the boxing method, the closure method adds tons of overhead despite appearing much simpler).

···

On 30 Mar 2016, at 18:11, Jason Sadler via swift-evolution <swift-evolution@swift.org> wrote:

Hi folks,

I have an issue with using a heterogeneous array of objects conforming to a protocol - I want to write an extension on Array (or CollectionType) that applies only when Element : MyProtocol, but I can’t call methods in that extension from an instance of [MyProtocol] because "Using ‘MyProtocol' as a concrete type conforming to protocol ‘MyProtocol' is not supported”

(For more background, my full use case can be seen in this gist: https://gist.github.com/sadlerjw/2cc16b4375b02fe7f400)

I’ve asked about this on swift-users (https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160321/001560.html) and got some good workarounds but no one was able to provide me with information on any future plans in swift to address this issue - whether that’s making protocols conform to themselves, or some other improved approach to heterogeneous collections. I wonder if anyone here can shed some light on this? (I’m new to the mailing lists, sorry!)

Thanks
Jason
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution