[swift-evolution] [swift-evolution-announce] [Review] SE-0057: Importing Objective-C Lightweight Generics

Douglas Gregor dgregor at apple.com
Fri Apr 1 01:04:03 CDT 2016


> On Mar 31, 2016, at 6:11 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> 	* What is your evaluation of the proposal?
> 
> I like it, but I have a couple of minor issues with the details.
> 
> The first is that type discovery does not support the full richness of either language's type system. Both languages allow a type to be either a class or a group of protocols, and Objective-C even allows one class + N protocols. I believe these methods should permit any valid Objective-C generic type to be expressed. That could be achieved by having two methods (plus class method variants):
> 
> 	- (nullable Class)classForGenericArgumentAtIndex:(NSUInteger)index;	// nil means id
> 	- (NSArray<Protocol*>*)protocolsForGenericArgumentAtIndex:(NSUInteger)index;

That’s a great point. Objective-C metadata doesn’t allow us to model it as a single entity, but a Class + array-of-protocols pair would suffice. I’d rather fold this into a single entrypoint, however, to reduce objc_msgSend overhead. I will note that I haven’t come across a generic Objective-C class that actually has protocol information in it, so it’s not clear whether this would actually get used.

> The second is the issue of extensions. Rather than rejecting the use of the generic type parameter, I think we would be better off treating it as though it were a nested typealias. That is, when you write this:
> 
> 	@interface MySet<__covariant ObjectType: id<NSCopying>> : NSObject
> 
> Then MySet.ObjectType is NSCopying. That would allow you to use ObjectType in extensions without particularly caring whether or not you were working with full generics.

I intentionally didn’t propose this because I think it would be very, very confusing. In extensions of Swift-defined generic types, ObjectType would have one meaning: it’s the type for the current specialization and it’s type-safe. In extensions of Objective-C generic types, ObjectType might have either the same meaning as in Swift-defined generic types (i.e., it’s type-safe) or it might be type-erased… and the answer could differ between a static method and an instance method in the same extension! Better to ban references to the generic parameter so it’s obvious to the user that it’s not a notion they can depend on.

> The third is that I'm troubled by the invisibility of this feature given its limitations. I understand why you don't want to implement full type erasure, but there should at least be some suggestion of the semantics in the generated headers:
> 
> 	class MySet<@erased ObjectType: NSCopying>: NSObject
> 
> @erased does not have to actually work in user-written code—it's just there in the generated header to mark the type parameter's special semantics.

I started with this, then eventually decided against it, because it’s just noise for the vast majority of users who just use the initializers, methods, and properties that exist on the type. It also implies that this is a general feature of the Swift generics system, which I don’t want: it’s limitations are an artifact of interoperability. 

> 
> Finally, this is a severable issue, but I think it's worth mentioning: it would be very helpful to expose generic classes back to Objective-C somehow. One of my projects has a CaseInsensitiveDictionary type written in Swift; I have reference-typed NSObject subclasses to expose it to Objective-C, but these can't be generic. Even lightweight generics, even exposed only to Objective-C, would make this code a lot better.

The main issue with this is that Objective-C cannot construct the specialized Swift metatype properly when allocating an instance of this class. We could perhaps export factory initializers to Objective-C that introduce additional “Class” parameters for each of the generic type arguments, so that the Swift-defined factory initializer could form the specialized Swift metatype, then allocate the instance. Or you could fake “alloc” for such types… it’s doable, but messy.

> 
>> 	* How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
> 
> Well, I've been drafting this email for several hours. Does that count?

Hah! I’ll take it.

	- Doug



More information about the swift-evolution mailing list