| # Objective-C Literals | |
| ## Introduction | |
| Three new features were introduced into clang at the same time: | |
| *NSNumber Literals* provide a syntax for creating `NSNumber` from | |
| scalar literal expressions; *Collection Literals* provide a short-hand | |
| for creating arrays and dictionaries; *Object Subscripting* provides a | |
| way to use subscripting with Objective-C objects. Users of Apple | |
| compiler releases can use these features starting with the Apple LLVM | |
| Compiler 4.0. Users of open-source LLVM.org compiler releases can use | |
| these features starting with clang v3.1. | |
| These language additions simplify common Objective-C programming | |
| patterns, make programs more concise, and improve the safety of | |
| container creation. | |
| This document describes how the features are implemented in clang, and | |
| how to use them in your own programs. | |
| ## NSNumber Literals | |
| The framework class `NSNumber` is used to wrap scalar values inside | |
| objects: signed and unsigned integers (`char`, `short`, `int`, | |
| `long`, `long long`), floating point numbers (`float`, | |
| `double`), and boolean values (`BOOL`, C++ `bool`). Scalar values | |
| wrapped in objects are also known as *boxed* values. | |
| In Objective-C, any character, numeric or boolean literal prefixed with | |
| the `'@'` character will evaluate to a pointer to an `NSNumber` | |
| object initialized with that value. C's type suffixes may be used to | |
| control the size of numeric literals. | |
| ### Examples | |
| The following program illustrates the rules for `NSNumber` literals: | |
| ```objc | |
| void main(int argc, const char *argv[]) { | |
| // character literals. | |
| NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z'] | |
| // integral literals. | |
| NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42] | |
| NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U] | |
| NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L] | |
| NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL] | |
| // floating point literals. | |
| NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F] | |
| NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535] | |
| // BOOL literals. | |
| NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES] | |
| NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO] | |
| #ifdef __cplusplus | |
| NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true] | |
| NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false] | |
| #endif | |
| } | |
| ``` | |
| ### Discussion | |
| NSNumber literals only support literal scalar values after the `'@'`. | |
| Consequently, `@INT_MAX` works, but `@INT_MIN` does not, because | |
| they are defined like this: | |
| ```objc | |
| #define INT_MAX 2147483647 /* max value for an int */ | |
| #define INT_MIN (-2147483647-1) /* min value for an int */ | |
| ``` | |
| The definition of `INT_MIN` is not a simple literal, but a | |
| parenthesized expression. Parenthesized expressions are supported using | |
| the [boxed expression](#boxed-expressions) syntax, which is | |
| described in the next section. | |
| Because `NSNumber` does not currently support wrapping `long double` | |
| values, the use of a `long double NSNumber` literal (e.g. | |
| `@123.23L`) will be rejected by the compiler. | |
| Previously, the `BOOL` type was simply a typedef for `signed char`, | |
| and `YES` and `NO` were macros that expand to `(BOOL)1` and | |
| `(BOOL)0` respectively. To support `@YES` and `@NO` expressions, | |
| these macros are now defined using new language keywords in | |
| `<objc/objc.h>`: | |
| ```objc | |
| #if __has_feature(objc_bool) | |
| #define YES __objc_yes | |
| #define NO __objc_no | |
| #else | |
| #define YES ((BOOL)1) | |
| #define NO ((BOOL)0) | |
| #endif | |
| ``` | |
| The compiler implicitly converts `__objc_yes` and `__objc_no` to | |
| `(BOOL)1` and `(BOOL)0`. The keywords are used to disambiguate | |
| `BOOL` and integer literals. | |
| Objective-C++ also supports `@true` and `@false` expressions, which | |
| are equivalent to `@YES` and `@NO`. | |
| ## Boxed Expressions | |
| Objective-C provides a new syntax for boxing C expressions: | |
| ```objc | |
| @( <expression> ) | |
| ``` | |
| Expressions of scalar (numeric, enumerated, BOOL), C string pointer | |
| and some C structures (via NSValue) are supported: | |
| ```objc | |
| // numbers. | |
| NSNumber *smallestInt = @(-INT_MAX - 1); // [NSNumber numberWithInt:(-INT_MAX - 1)] | |
| NSNumber *piOverTwo = @(M_PI / 2); // [NSNumber numberWithDouble:(M_PI / 2)] | |
| // enumerated types. | |
| typedef enum { Red, Green, Blue } Color; | |
| NSNumber *favoriteColor = @(Green); // [NSNumber numberWithInt:((int)Green)] | |
| // strings. | |
| NSString *path = @(getenv("PATH")); // [NSString stringWithUTF8String:(getenv("PATH"))] | |
| NSArray *pathComponents = [path componentsSeparatedByString:@":"]; | |
| // structs. | |
| NSValue *center = @(view.center); // Point p = view.center; | |
| // [NSValue valueWithBytes:&p objCType:@encode(Point)]; | |
| NSValue *frame = @(view.frame); // Rect r = view.frame; | |
| // [NSValue valueWithBytes:&r objCType:@encode(Rect)]; | |
| ``` | |
| ### Boxed Enums | |
| Cocoa frameworks frequently define constant values using *enums.* | |
| Although enum values are integral, they may not be used directly as | |
| boxed literals (this avoids conflicts with future `'@'`-prefixed | |
| Objective-C keywords). Instead, an enum value must be placed inside a | |
| boxed expression. The following example demonstrates configuring an | |
| `AVAudioRecorder` using a dictionary that contains a boxed enumeration | |
| value: | |
| ```objc | |
| enum { | |
| AVAudioQualityMin = 0, | |
| AVAudioQualityLow = 0x20, | |
| AVAudioQualityMedium = 0x40, | |
| AVAudioQualityHigh = 0x60, | |
| AVAudioQualityMax = 0x7F | |
| }; | |
| - (AVAudioRecorder *)recordToFile:(NSURL *)fileURL { | |
| NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) }; | |
| return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL]; | |
| } | |
| ``` | |
| The expression `@(AVAudioQualityMax)` converts `AVAudioQualityMax` | |
| to an integer type, and boxes the value accordingly. If the enum has a | |
| {ref}`fixed underlying type <objc-fixed-enum>` as in: | |
| ```objc | |
| typedef enum : unsigned char { Red, Green, Blue } Color; | |
| NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:] | |
| ``` | |
| then the fixed underlying type will be used to select the correct | |
| `NSNumber` creation method. | |
| Boxing a value of enum type will result in a `NSNumber` pointer with a | |
| creation method according to the underlying type of the enum, which can | |
| be a {ref}`fixed underlying type <objc-fixed-enum>` | |
| or a compiler-defined integer type capable of representing the values of | |
| all the members of the enumeration: | |
| ```objc | |
| typedef enum : unsigned char { Red, Green, Blue } Color; | |
| Color col = Red; | |
| NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:] | |
| ``` | |
| ### Boxed C Strings | |
| A C string literal prefixed by the `'@'` token denotes an `NSString` | |
| literal in the same way a numeric literal prefixed by the `'@'` token | |
| denotes an `NSNumber` literal. When the type of the parenthesized | |
| expression is `(char *)` or `(const char *)`, the result of the | |
| boxed expression is a pointer to an `NSString` object containing | |
| equivalent character data, which is assumed to be '\\0'-terminated and | |
| UTF-8 encoded. The following example converts C-style command line | |
| arguments into `NSString` objects. | |
| ```objc | |
| // Partition command line arguments into positional and option arguments. | |
| NSMutableArray *args = [NSMutableArray new]; | |
| NSMutableDictionary *options = [NSMutableDictionary new]; | |
| while (--argc) { | |
| const char *arg = *++argv; | |
| if (strncmp(arg, "--", 2) == 0) { | |
| options[@(arg + 2)] = @(*++argv); // --key value | |
| } else { | |
| [args addObject:@(arg)]; // positional argument | |
| } | |
| } | |
| ``` | |
| As with all C pointers, character pointer expressions can involve | |
| arbitrary pointer arithmetic, therefore programmers must ensure that the | |
| character data is valid. Passing `NULL` as the character pointer will | |
| raise an exception at runtime. When possible, the compiler will reject | |
| `NULL` character pointers used in boxed expressions. | |
| ### Boxed C Structures | |
| Boxed expressions support construction of NSValue objects. | |
| It said that C structures can be used, the only requirement is: | |
| structure should be marked with `objc_boxable` attribute. | |
| To support older version of frameworks and/or third-party libraries | |
| you may need to add the attribute via `typedef`. | |
| ```objc | |
| struct __attribute__((objc_boxable)) Point { | |
| // ... | |
| }; | |
| typedef struct __attribute__((objc_boxable)) _Size { | |
| // ... | |
| } Size; | |
| typedef struct _Rect { | |
| // ... | |
| } Rect; | |
| struct Point p; | |
| NSValue *point = @(p); // ok | |
| Size s; | |
| NSValue *size = @(s); // ok | |
| Rect r; | |
| NSValue *bad_rect = @(r); // error | |
| typedef struct __attribute__((objc_boxable)) _Rect Rect; | |
| NSValue *good_rect = @(r); // ok | |
| ``` | |
| ## Container Literals | |
| Objective-C now supports a new expression syntax for creating immutable | |
| array and dictionary container objects. | |
| ### Examples | |
| Immutable array expression: | |
| ```objc | |
| NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ]; | |
| ``` | |
| This creates an `NSArray` with 3 elements. The comma-separated | |
| sub-expressions of an array literal can be any Objective-C object | |
| pointer typed expression. | |
| Immutable dictionary expression: | |
| ```objc | |
| NSDictionary *dictionary = @{ | |
| @"name" : NSUserName(), | |
| @"date" : [NSDate date], | |
| @"processInfo" : [NSProcessInfo processInfo] | |
| }; | |
| ``` | |
| This creates an `NSDictionary` with 3 key/value pairs. Value | |
| sub-expressions of a dictionary literal must be Objective-C object | |
| pointer typed, as in array literals. Key sub-expressions must be of an | |
| Objective-C object pointer type that implements the | |
| `<NSCopying>` protocol. | |
| ### Discussion | |
| Neither keys nor values can have the value `nil` in containers. If the | |
| compiler can prove that a key or value is `nil` at compile time, then | |
| a warning will be emitted. Otherwise, a runtime error will occur. | |
| Using array and dictionary literals is safer than the variadic creation | |
| forms commonly in use today. Array literal expressions expand to calls | |
| to `+[NSArray arrayWithObjects:count:]`, which validates that all | |
| objects are non-`nil`. The variadic form, | |
| `+[NSArray arrayWithObjects:]` uses `nil` as an argument list | |
| terminator, which can lead to malformed array objects. Dictionary | |
| literals are similarly created with | |
| `+[NSDictionary dictionaryWithObjects:forKeys:count:]` which validates | |
| all objects and keys, unlike | |
| `+[NSDictionary dictionaryWithObjectsAndKeys:]` which also uses a | |
| `nil` parameter as an argument list terminator. | |
| ## Object Subscripting | |
| Objective-C object pointer values can now be used with C's subscripting | |
| operator. | |
| ### Examples | |
| The following code demonstrates the use of object subscripting syntax | |
| with `NSMutableArray` and `NSMutableDictionary` objects: | |
| ```objc | |
| NSMutableArray *array = ...; | |
| NSUInteger idx = ...; | |
| id newObject = ...; | |
| id oldObject = array[idx]; | |
| array[idx] = newObject; // replace oldObject with newObject | |
| NSMutableDictionary *dictionary = ...; | |
| NSString *key = ...; | |
| oldObject = dictionary[key]; | |
| dictionary[key] = newObject; // replace oldObject with newObject | |
| ``` | |
| The next section explains how subscripting expressions map to accessor | |
| methods. | |
| ### Subscripting Methods | |
| Objective-C supports two kinds of subscript expressions: *array-style* | |
| subscript expressions use integer typed subscripts; *dictionary-style* | |
| subscript expressions use Objective-C object pointer typed subscripts. | |
| Each type of subscript expression is mapped to a message send using a | |
| predefined selector. The advantage of this design is flexibility: class | |
| designers are free to introduce subscripting by declaring methods or by | |
| adopting protocols. Moreover, because the method names are selected by | |
| the type of the subscript, an object can be subscripted using both array | |
| and dictionary styles. | |
| #### Array-Style Subscripting | |
| When the subscript operand has an integral type, the expression is | |
| rewritten to use one of two different selectors, depending on whether | |
| the element is being read or written. When an expression reads an | |
| element using an integral index, as in the following example: | |
| ```objc | |
| NSUInteger idx = ...; | |
| id value = object[idx]; | |
| ``` | |
| it is translated into a call to `objectAtIndexedSubscript:` | |
| ```objc | |
| id value = [object objectAtIndexedSubscript:idx]; | |
| ``` | |
| When an expression writes an element using an integral index: | |
| ```objc | |
| object[idx] = newValue; | |
| ``` | |
| it is translated to a call to `setObject:atIndexedSubscript:` | |
| ```objc | |
| [object setObject:newValue atIndexedSubscript:idx]; | |
| ``` | |
| These message sends are then type-checked and performed just like | |
| explicit message sends. The method used for objectAtIndexedSubscript: | |
| must be declared with an argument of integral type and a return value of | |
| some Objective-C object pointer type. The method used for | |
| setObject:atIndexedSubscript: must be declared with its first argument | |
| having some Objective-C pointer type and its second argument having | |
| integral type. | |
| The meaning of indexes is left up to the declaring class. The compiler | |
| will coerce the index to the appropriate argument type of the method it | |
| uses for type-checking. For an instance of `NSArray`, reading an | |
| element using an index outside the range `[0, array.count)` will raise | |
| an exception. For an instance of `NSMutableArray`, assigning to an | |
| element using an index within this range will replace that element, but | |
| assigning to an element using an index outside this range will raise an | |
| exception; no syntax is provided for inserting, appending, or removing | |
| elements for mutable arrays. | |
| A class need not declare both methods in order to take advantage of this | |
| language feature. For example, the class `NSArray` declares only | |
| `objectAtIndexedSubscript:`, so that assignments to elements will fail | |
| to type-check; moreover, its subclass `NSMutableArray` declares | |
| `setObject:atIndexedSubscript:`. | |
| #### Dictionary-Style Subscripting | |
| When the subscript operand has an Objective-C object pointer type, the | |
| expression is rewritten to use one of two different selectors, depending | |
| on whether the element is being read from or written to. When an | |
| expression reads an element using an Objective-C object pointer | |
| subscript operand, as in the following example: | |
| ```objc | |
| id key = ...; | |
| id value = object[key]; | |
| ``` | |
| it is translated into a call to the `objectForKeyedSubscript:` method: | |
| ```objc | |
| id value = [object objectForKeyedSubscript:key]; | |
| ``` | |
| When an expression writes an element using an Objective-C object pointer | |
| subscript: | |
| ```objc | |
| object[key] = newValue; | |
| ``` | |
| it is translated to a call to `setObject:forKeyedSubscript:` | |
| ```objc | |
| [object setObject:newValue forKeyedSubscript:key]; | |
| ``` | |
| The behavior of `setObject:forKeyedSubscript:` is class-specific; but | |
| in general it should replace an existing value if one is already | |
| associated with a key, otherwise it should add a new value for the key. | |
| No syntax is provided for removing elements from mutable dictionaries. | |
| ### Discussion | |
| An Objective-C subscript expression occurs when the base operand of the | |
| C subscript operator has an Objective-C object pointer type. Since this | |
| potentially collides with pointer arithmetic on the value, these | |
| expressions are only supported under the modern Objective-C runtime, | |
| which categorically forbids such arithmetic. | |
| Currently, only subscripts of integral or Objective-C object pointer | |
| type are supported. In C++, a class type can be used if it has a single | |
| conversion function to an integral or Objective-C pointer type, in which | |
| case that conversion is applied and analysis continues as appropriate. | |
| Otherwise, the expression is ill-formed. | |
| An Objective-C object subscript expression is always an l-value. If the | |
| expression appears on the left-hand side of a simple assignment operator | |
| (=), the element is written as described below. If the expression | |
| appears on the left-hand side of a compound assignment operator (e.g. | |
| +=), the program is ill-formed, because the result of reading an element | |
| is always an Objective-C object pointer and no binary operators are | |
| legal on such pointers. If the expression appears in any other position, | |
| the element is read as described below. It is an error to take the | |
| address of a subscript expression, or (in C++) to bind a reference to | |
| it. | |
| Programs can use object subscripting with Objective-C object pointers of | |
| type `id`. Normal dynamic message send rules apply; the compiler must | |
| see *some* declaration of the subscripting methods, and will pick the | |
| declaration seen first. | |
| ## Caveats | |
| Objects created using the literal or boxed expression syntax are not | |
| guaranteed to be uniqued by the runtime, but nor are they guaranteed to | |
| be newly-allocated. As such, the result of performing direct comparisons | |
| against the location of an object literal (using `==`, `!=`, `<`, | |
| `<=`, `>`, or `>=`) is not well-defined. This is usually a simple | |
| mistake in code that intended to call the `isEqual:` method (or the | |
| `compare:` method). | |
| This caveat applies to compile-time string literals as well. | |
| Historically, string literals (using the `@"..."` syntax) have been | |
| uniqued across translation units during linking. This is an | |
| implementation detail of the compiler and should not be relied upon. If | |
| you are using such code, please use global string constants instead | |
| (`NSString * const MyConst = @"..."`) or use `isEqual:`. | |
| ## Grammar Additions | |
| To support the new syntax described above, the Objective-C | |
| `@`-expression grammar has the following new productions: | |
| ``` | |
| objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal) | |
| ; | |
| object-literal : ('+' | '-')? numeric-constant | |
| | character-constant | |
| | boolean-constant | |
| | array-literal | |
| | dictionary-literal | |
| ; | |
| boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false' /* boolean keywords. */ | |
| ; | |
| array-literal : '[' assignment-expression-list ']' | |
| ; | |
| assignment-expression-list : assignment-expression (',' assignment-expression-list)? | |
| | /* empty */ | |
| ; | |
| dictionary-literal : '{' key-value-list '}' | |
| ; | |
| key-value-list : key-value-pair (',' key-value-list)? | |
| | /* empty */ | |
| ; | |
| key-value-pair : assignment-expression ':' assignment-expression | |
| ; | |
| ``` | |
| Note: `@true` and `@false` are only supported in Objective-C++. | |
| ## Availability Checks | |
| Programs test for the new features by using clang's \_\_has_feature | |
| checks. Here are examples of their use: | |
| ```objc | |
| #if __has_feature(objc_array_literals) | |
| // new way. | |
| NSArray *elements = @[ @"H", @"He", @"O", @"C" ]; | |
| #else | |
| // old way (equivalent). | |
| id objects[] = { @"H", @"He", @"O", @"C" }; | |
| NSArray *elements = [NSArray arrayWithObjects:objects count:4]; | |
| #endif | |
| #if __has_feature(objc_dictionary_literals) | |
| // new way. | |
| NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 }; | |
| #else | |
| // old way (equivalent). | |
| id keys[] = { @"H", @"He", @"O", @"C" }; | |
| id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026], | |
| [NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] }; | |
| NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4]; | |
| #endif | |
| #if __has_feature(objc_subscripting) | |
| NSUInteger i, count = elements.count; | |
| for (i = 0; i < count; ++i) { | |
| NSString *element = elements[i]; | |
| NSNumber *mass = masses[element]; | |
| NSLog(@"the mass of %@ is %@", element, mass); | |
| } | |
| #else | |
| NSUInteger i, count = [elements count]; | |
| for (i = 0; i < count; ++i) { | |
| NSString *element = [elements objectAtIndex:i]; | |
| NSNumber *mass = [masses objectForKey:element]; | |
| NSLog(@"the mass of %@ is %@", element, mass); | |
| } | |
| #endif | |
| #if __has_attribute(objc_boxable) | |
| typedef struct __attribute__((objc_boxable)) _Rect Rect; | |
| #endif | |
| #if __has_feature(objc_boxed_nsvalue_expressions) | |
| CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"]; | |
| animation.fromValue = @(layer.position); | |
| animation.toValue = @(newPosition); | |
| [layer addAnimation:animation forKey:@"move"]; | |
| #else | |
| CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"]; | |
| animation.fromValue = [NSValue valueWithCGPoint:layer.position]; | |
| animation.toValue = [NSValue valueWithCGPoint:newPosition]; | |
| [layer addAnimation:animation forKey:@"move"]; | |
| #endif | |
| ``` | |
| Code can use also `__has_feature(objc_bool)` to check for the | |
| availability of numeric literals support. This checks for the new | |
| `__objc_yes / __objc_no` keywords, which enable the use of | |
| `@YES / @NO` literals. | |
| To check whether boxed expressions are supported, use | |
| `__has_feature(objc_boxed_expressions)` feature macro. |