[swift-evolution] [Pitch] Bridging nil to Objective-C Primitives

Philippe Hausler phausler at apple.com
Tue Feb 14 13:08:29 CST 2017

The feature in this case I would claim is independent of the adopters. Personally I think this would be a useful feature to allow for better exposition into swift but also more robust objective-c APIs.

Something to consider here is that not all NSUIntegers can be NSNotFound, sometimes the return value is 0. It would be interesting to consider that _Nullable would be parameterized via a constant expression. This is a straw man refinement here (the exact spelling would be something we would have to audit the way it is implemented and likely use macros to compose the right nullability concepts)

Lets take for example this API:

+ (NSInteger)writePropertyList:(id)plist toStream:(NSOutputStream *)stream format:(NSPropertyListFormat)format options:(NSPropertyListWriteOptions)opt error:(out NSError **)error;

The return value here would be 0 if an error occurs. So the nullability value would be 0.

+ (nullable(0) NSInteger)writePropertyList:(id)plist toStream:(NSOutputStream *)stream format:(NSPropertyListFormat)format options:(NSPropertyListWriteOptions)opt error:(out NSError **)error;

But other APIs like you indicated:

- (NSUInteger)indexOfObject:(ObjectType)anObject;

Could be converted to:

- (nullable(NSNotFound) NSUInteger)indexOfObject:(ObjectType)anObject;

Which would immediately be an indication to the reader what the “null” value would be represented as. Of course your concept of type aliases might be a decent way to group concepts together but if lets say there was an index type for NSArray; obviously you might want a index return value to be nullable but it would be a bit confusing to take a nullable parameter into certain APIs.

Given a concept of NSArrayIndex as you suggested (that being nullable) would have the problem that 

- (ObjectType)objectAtIndex:(NSUInteger)index;

Would either incorrectly indicate it would be nullable or it would have a different type. 

There would be other cases where structural types might need a nullable placeholder value, e.g. NSRange with a location of NSNotFound and a length of 0 (however that strictly isn’t correct since it is just the location that indicates null-ness.. but that is probably more of an implementation detail and should probably be corrected imho).

There could also be cases where an API returns either an object of a specific type or NSNull as a placeholder. This would be nice to be able to express as a nullable type especially in generics. For example: `NSArray<_Nullable(NSNull *) Foo *> *` could be a neat way to express `Array<Foo?>` which cannot be expressed currently.

Overall I think this could really reduce some of the overlays for all the frameworks on Mac OS X and iOS, improve the expressivity of Objective-C APIs, offer more accurate bridged representations, and generally give API authors an opportunity to more correctly represent what should be exposed in Swift without needing to write overlays that could easily have poor interaction with things like subclassing or delegation.

As a side note: I am not certain if the parameterization of nullability annotations would even be possible in the current compiler implementations or if it would be easier to use an attribute instead (that would be left to implementation detail).

I would guess that if this feature would be available it would take a combined effort from all API maintainers to annotate their return values and any un-annotated shouldn’t be exposed as a IOU since they have non nil values already. Furthermore the timeframe to do so would probably be independent of the implementation of this type of feature. 

Those caveats aside - I think it would be a fantastic tool in the toolbox!

> On Feb 14, 2017, at 10:41 AM, Jeff Kelley via swift-evolution <swift-evolution at swift.org> wrote:
> On Mon, Feb 13, 2017 at 11:53 PM, Rod Brown <rodney.brown6 at icloud.com <mailto:rodney.brown6 at icloud.com>> wrote:
> I think the biggest problem we're going to face with this one is changes to Objective-C are out of scope for Swift Evolution. Apple tend to be the ones in control of the development of new Objective-C features and compatibility because they control the compiler.
> I don’t think that Objective-C changes are out of bounds when Swift is involved—see my past, accepted proposal at SE-0033 <https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md>.
> That said, as a request to Apple for this change, I think it's a reasonable idea for Ints, but I'm not sure of its feasibility for other types. Could the API be descriptive enough to cover enough types? (Eg CGRectNull)
> It’s an open-and-shut case for any standard primitive, but structs like CGRect are where it starts to get tricky. I see that CGRect conforms to Equatable when it’s imported into Swift; perhaps that could be enough for this to work? If the translation to and from nil happens in the Swift side, I can see Equatable as a reasonable requirement for the type.
> On 14 Feb 2017, at 2:33 pm, Jeff Kelley via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> Hi all,
>> 	I don’t have a formal proposal written up yet, but in my continued quest to make better-annotated Objective-C code, I had an idea for bridging nil with primitives. Since in Objective-C we often use constant values to represent invalid values or nil, the most obvious being NSNotFound, could we use that as a shorthand for nil? Something like this for NSArray:
>> - (NSUInteger NS_SWIFT_NIL(NSNotFound))indexOfObject:(ObjectType)anObject;
>> 	This is a little verbose, so it could also work with a typedef:
>> typedef NSUInteger NS_SWIFT_NIL(NSNotFound) NSArrayIndex;
>> - (NSArrayIndex)indexOfObject:(ObjectType)anObject;
>> 	This would change the existing Swift interface to return an Int? instead of an Int. I see this as working both ways—converting these values to nil when returning from Objective-C to Swift, and sending these values instead of nil when Swift calls into Objective-C code.
>> 	Is this worth writing up a proposal for? Is another, better method already in someone’s mind?
>> Jeff Kelley
>> SlaunchaMan at gmail.com <mailto:SlaunchaMan at gmail.com> | @SlaunchaMan <https://twitter.com/SlaunchaMan> | jeffkelley.org <http://jeffkelley.org/>
> Jeff Kelley
> SlaunchaMan at gmail.com <mailto:SlaunchaMan at gmail.com> | @SlaunchaMan <https://twitter.com/SlaunchaMan> | jeffkelley.org <http://jeffkelley.org/>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170214/27d08cf7/attachment.html>

More information about the swift-evolution mailing list