For those who (like me) didn’t really pay attention to the WWDC last month, 
Apple has just sent patches for ‘lightweight’ (type-erasing) generic for 
Objective-C to the Clang list (see forwarded message).  These don’t require any 
runtime support, so they should Just Work™ with GNUstep, though we’ll want to 
add things to various headers to support them (these can be done with macros to 
support older compilers - I’ll put together a patch once it’s landed in clang 
and is easier to test).

Given that Objective-C++ works well now with ARC, I’m less interested in this 
than I would have been 10 years ago - I tend to use C++ collection classes for 
Objective-C objects in new code - but it’s still quite a nice feature.

David

> Hi all,
> 
> Last month, Apple introduced a new lightweight generics system into 
> Objective-C. The attached patch series provides the complete implementation 
> of this feature, the related “kindof” types feature, supporting warnings, 
> test-cases, and so on. It should get us back to the point where we can parse 
> the headers for Apple’s latest SDKs.
> 
> For those of you wondering what this whole lightweight generics thing is, I 
> suggest either watching the following WWDC video starting at @21:45:
> 
>       https://developer.apple.com/videos/wwdc/2015/?id=401 
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__developer.apple.com_videos_wwdc_2015_-3Fid-3D401&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=CnzuN65ENJ1H9py9XLiRvC_UQz6u3oG6GUNn7_wosSM&m=gksuXWwW39OdeK_NxENNyU46455v_XexMqDHmfEJNjA&s=ALq4TVlEqBaa3eyce5u1amIVjdR5youDJg0j05H4htQ&e=>
> 
> or keep reading for an explanation.
> 
> Lightweight generics allows Objective-C classes to be parameterized, e.g., 
> NSArray can be parameterized on the type of its elements:
> 
>       @interface NSArray<ObjectType> : NSObject
>       -(ObjectType)objectAtIndex:(NSInteger)index;
>       @end
> 
> Objective-C classes, categories, extensions, and forward declarations can all 
> specify type parameters. Naturally, the type parameters across different 
> declarations associated with the same class must be consistent.
> 
> For a given parameterized class, one can provide type arguments, e.g., to 
> state the type of the elements of an NSArray:
> 
>       NSArray<NSString *> *strings;
>       NSArray<NSNumber *> *numbers;
> 
> Naturally, messaging an object of specialized type substitutes the type 
> arguments for the type parameters, e.g.,
> 
>       [strings objectAtIndex: 0]; // produces an NSString *
>       [numbers objectAtIndex: 0]; // produces an NSNumber *
> 
> One can, of course, leave the type arguments unspecified:
> 
>       NSArray *array;
> 
> Each of the types NSArray<NSString *>, NSArray<NSNumber *>, and NSArray are 
> distinct types. There are implicit conversions between the “specialized” 
> types (NSArray<NSString *>, NSArray<NSNumber *>) and the “unspecialized” type 
> (NSArray *), but not between different specialized types. For example:
> 
>       array = strings; // okay, dropping type arguments
>       numbers = array; // okay, adding type arguments
>       strings = numbers; // not okay! NSArray<NSString *> and 
> NSArray<NSNumber *> are incompatible types
> 
> The “lightweight” in lightweight generics comes from the implementation 
> model, which is based on type erasure (a la Java Generics). All of the type 
> argument information is completely erased by IR generation, so this feature 
> requires no runtime or metadata changes. Obviously, this—along with the 
> implicit conversion rules above—means that some "obvious” errors will be 
> missed by the type checker (and won’t be enforced by the runtime). For 
> example, the sequence “array = strings; numbers = array;” is obviously bogus: 
> the elements cannot be both NSStrings and NSNumbers. Sema won’t catch this, 
> just like Sema wouldn’t catch an assignment chain that converts an NSNumber 
> to an NSString by way of ‘id’.
> 
> Type parameters have a few advanced features. First of all, they can have 
> upper bounds, such that any type argument must be a subtype of the upper 
> bound of the corresponding type parameter. For example:
> 
>       @interface MyMap<KeyType : id<NSCopying>, ObjectType>
>       -(KeyType)firstKeyForObject:(ObjectType)object; // yes, this is a weird 
> example; explanation below
>       @end
> 
> It’s an error to form a MyMap<T, U> where T isn’t a subtype of id<NSCopying>. 
> When the type bound is omitted, it is “id”, i.e., all type 
> parameters/arguments are all Objective-C objects. Type bounds are also 
> important when using unspecialized types (e.g., MyMap *); we’ll come back to 
> that later.
> 
> Type parameters can also be co- or contra-variant, similarly to C#’s generic 
> type parameters (see, e.g., 
> https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx) 
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__msdn.microsoft.com_en-2Dus_library_dd799517-28v-3Dvs.110-29.aspx-29&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=CnzuN65ENJ1H9py9XLiRvC_UQz6u3oG6GUNn7_wosSM&m=gksuXWwW39OdeK_NxENNyU46455v_XexMqDHmfEJNjA&s=lLGp0NGVuw3Ee3R8nbuaDTRg6Jp-Pft4EJs7bdXavL4&e=>.
>  This is particularly useful for the immutable collection classes, which 
> we’ll use for exposition purposes. NSArray is actually declared as:
> 
>       @interface NSArray<__covariant ObjectType> : NSObject
>       -(ObjectType)objectAtIndex:(NSInteger)index;
>       @end
> 
> Because ObjectType is covariant, NSArray<T> is implicitly convertible to 
> NSArray<U> when T is a subtype of U, which allows, e.g.,
> 
>       NSArray<NSMutableString *> *mutStrings;
>       NSArray<NSString *> *strings;
>       strings = mutStrings; // okay, because ObjectType is covariant (and 
> NSArray is an immutable collection)
> 
> Contravariant type parameters go the opposite way, e.g., NSArray<T> is 
> implicitly convertible to NSArray<U> when U is a subtype of T.
> 
> Objective-C lightweight generics also involves a related feature called 
> “kindof” types, which strike a balance between “id” and specific Objective-C 
> pointer types. For example, given:
> 
>       __kindof NSString *kindofStr;
> 
> we can implicitly convert to supertypes *and* subtypes, but not unrelated 
> types. For example:
> 
>       NSObject *object = kindofStr; // okay, implicitly converting to 
> supertype
>       NSMutableString *mutString = kindofStr; // okay, implicitly converting 
> to subtype
>       NSNumber *number = kindofStr; // not okay! NSString and NSNumber are 
> incompatible
> 
> Naturally, the features compose: one can create an array of kindof types, 
> e.g.,
> 
>       NSArray<__kindof NSValue *> *values;
> 
> which can be *very* helpful when adopting lightweight generics. Kindof types 
> are also important when working with unspecialized types. For example, let’s 
> invent a class that only wants to work with subclasses of ‘View’:
> 
>       @interface SomeClass<T : View *> // T must be View or a subclass thereof
>       - (T)view;
>       @end
> 
> As noted earlier, when we message SomeClass, we substitute in the type 
> arguments for the type parameters, e.g.,
> 
>       SomeClass<Button *> *sc;
>       [sc view]; // produces a "Button *"
> 
> But what happens if we don’t have type arguments, because we’re messaging an 
> object of type ’SomeClass *’? We produce a __kindoftype from the type bound, 
> which gives us good static type information without forcing the user to 
> introduce a large number of casts:
> 
>       SomeClass *sc;
>       [sc view]; // produces a "__kindof View *"
> 
> 
> That’s most of it! I’ll be happy to answer any questions. Actual coherent 
> documentation is forthcoming, but we wanted to get this implementation out 
> there for people to play with.
> 
> The patches are fairly large, since this is a nontrivial feature. I’ve broken 
> it up into logical pieces, which are, roughly:
> 
>       1) Type parameter parsing, ASTs, etc.
>       2) Type argument handling
>       3) Substitution of type arguments for parameters when using specialized 
> types
>       4) Reworking our handling of the ternary operator on Objective-C 
> pointer types
>       5) Interaction between C++ templates and Objective-C lightweight 
> generics
>       6/7) Warnings for lightweight generics
>       8) Kindof types
>       9) Co- and contra-variant type parameters
>       10) Annoying workaround for old Clang versions that apparently still 
> need to build with
> 
> Detailed patch review should go to cfe-commits, so we can keep the discussion 
> here more high-level.
> 
>       - Doug




-- Sent from my STANTEC-ZEBRA

_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
https://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to