Request for a simple, Foundation-friendly enumerated type

Originator:iamleeg
Number:rdar://8779321 Date Originated:16/12/2010
Status:Open Resolved:
Product:iPad SDK Product Version:N/A
Classification:Enhancement Reproducible:Not Applicable
 
16-Dec-2010 10:54 PM Graham Lee:
Summary:

Many applications need to use enumerated types, often to implement some variant of the State pattern. An obvious example in iOS would be requiring different view controller behaviour depending on screen orientation. Traditional C enumerations would look like this:

enum { GLScreenOrientationLandscape, GLScreenOrientationPortrait };

but these have various problems: binary compatibility is hard, the size of storage used is not well-defined (hence Foundation using typedefs for its enums), the types are unbounded, nonsensical operations are possible like:

x = GLScreenOrientationLandscape * GLScreenOrientationPortrait;

and most annoyingly for Objective-C code, to work with these enums means repetitive, error-prone and inefficient boxing code using NSNumber or NSValue.

Proposed solution:

An Objective-C specific @enum type, which creates static, immutable instances. So you could have:

@enum GLScreenOrientation {Landscape, Portrait};

which creates a class like this:

@interface GLScreenOrientation: NSObject <NSCopying>
+ (GLScreenOrientation *)Landscape;
+ (GLScreenOrientation *)Portrait;
+ (NSSet *)values;
@end

Benefits: the main benefit is code brevity. Here is some code using C enums:

NSNumber *viewHeight = [heights objectForKey: [NSNumber numberWithInteger: GLScreenOrientationLandscape]];

if ([orientation integerValue] == GLScreenOrientationLandscape) {

switch ([orientation integerValue]) {
case (GLScreenOrientationLandscape):
break;
case (GLScreenOrientationPortrait):
break;
default: //handle surprising value
}

for (NSInteger i=GLScreenOrientationLandscape; i <=GLScreenOrientationPortrait; i++) {
  // hope I got those the right way around, that there are no gaps, and that I didn't miss any....
}

and a case-by-case replacement with my proposed enumeration type:

NSNumber *viewHeight = [heights objectForKey: [GLScreenOrientation Landscape]];

if (orientation == [GLScreenOrientation Landscape]) //as the instances are static, this is permitted

if (orientation == [GLScreenOrientation Landscape]) {}
else if (orientation == [GLScreenOrientation Portrait]) {}
//no need to handle the default case, there isn't one

for (GLScreenOrientation *orientation in [GLScreenOrientation values]) {}

The other benefit is safety. Notice that in the case of the switch and for expressions, using C enumerated types is awkward because in each case you might encounter values that aren't part of the enumeration. Using my proposed type, this problem is mitigated. It is not possible to request a value that isn't part of the enumeration because you are restricted to using the class methods. The use of the new types can be checked by the compiler in a way that C-style enums can't: if your code expects a GLScreenOrientation instance, then that is what it must get.

The amount of storage used in each case isn't going to differ much, as the enumeration instances are Flyweights so there just needs to be one static instance per value written into the compiled object.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!