| ==================== |
| 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: |
| |
| .. code-block:: 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: |
| |
| .. code-block:: 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 <#objc_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>``: |
| |
| .. code-block:: 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: |
| |
| .. code-block:: objc |
| |
| @( <expression> ) |
| |
| Expressions of scalar (numeric, enumerated, BOOL) and C string pointer |
| types are supported: |
| |
| .. code-block:: 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:@":"]; |
| |
| 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: |
| |
| .. code-block:: 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: |
| |
| .. code-block:: 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: |
| |
| .. code-block:: 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. |
| |
| .. code-block:: 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. |
| |
| Container Literals |
| ================== |
| |
| Objective-C now supports a new expression syntax for creating immutable |
| array and dictionary container objects. |
| |
| Examples |
| -------- |
| |
| Immutable array expression: |
| |
| .. code-block:: 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: |
| |
| .. code-block:: 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: |
| |
| .. code-block:: 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: |
| |
| .. code-block:: objc |
| |
| NSUInteger idx = ...; |
| id value = object[idx]; |
| |
| it is translated into a call to ``objectAtIndexedSubscript:`` |
| |
| .. code-block:: objc |
| |
| id value = [object objectAtIndexedSubscript:idx]; |
| |
| When an expression writes an element using an integral index: |
| |
| .. code-block:: objc |
| |
| object[idx] = newValue; |
| |
| it is translated to a call to ``setObject:atIndexedSubscript:`` |
| |
| .. code-block:: 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: |
| |
| .. code-block:: objc |
| |
| id key = ...; |
| id value = object[key]; |
| |
| it is translated into a call to the ``objectForKeyedSubscript:`` method: |
| |
| .. code-block:: objc |
| |
| id value = [object objectForKeyedSubscript:key]; |
| |
| When an expression writes an element using an Objective-C object pointer |
| subscript: |
| |
| .. code-block:: objc |
| |
| object[key] = newValue; |
| |
| it is translated to a call to ``setObject:forKeyedSubscript:`` |
| |
| .. code-block:: 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: |
| |
| .. code-block:: 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 |
| |
| 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. |