brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.0 KiB · 9fe7f66 Raw
607 lines · plain
1====================2Objective-C Literals3====================4 5Introduction6============7 8Three new features were introduced into clang at the same time:9*NSNumber Literals* provide a syntax for creating ``NSNumber`` from10scalar literal expressions; *Collection Literals* provide a short-hand11for creating arrays and dictionaries; *Object Subscripting* provides a12way to use subscripting with Objective-C objects. Users of Apple13compiler releases can use these features starting with the Apple LLVM14Compiler 4.0. Users of open-source LLVM.org compiler releases can use15these features starting with clang v3.1.16 17These language additions simplify common Objective-C programming18patterns, make programs more concise, and improve the safety of19container creation.20 21This document describes how the features are implemented in clang, and22how to use them in your own programs.23 24NSNumber Literals25=================26 27The framework class ``NSNumber`` is used to wrap scalar values inside28objects: signed and unsigned integers (``char``, ``short``, ``int``,29``long``, ``long long``), floating point numbers (``float``,30``double``), and boolean values (``BOOL``, C++ ``bool``). Scalar values31wrapped in objects are also known as *boxed* values.32 33In Objective-C, any character, numeric or boolean literal prefixed with34the ``'@'`` character will evaluate to a pointer to an ``NSNumber``35object initialized with that value. C's type suffixes may be used to36control the size of numeric literals.37 38Examples39--------40 41The following program illustrates the rules for ``NSNumber`` literals:42 43.. code-block:: objc44 45    void main(int argc, const char *argv[]) {46      // character literals.47      NSNumber *theLetterZ = @'Z';          // equivalent to [NSNumber numberWithChar:'Z']48 49      // integral literals.50      NSNumber *fortyTwo = @42;             // equivalent to [NSNumber numberWithInt:42]51      NSNumber *fortyTwoUnsigned = @42U;    // equivalent to [NSNumber numberWithUnsignedInt:42U]52      NSNumber *fortyTwoLong = @42L;        // equivalent to [NSNumber numberWithLong:42L]53      NSNumber *fortyTwoLongLong = @42LL;   // equivalent to [NSNumber numberWithLongLong:42LL]54 55      // floating point literals.56      NSNumber *piFloat = @3.141592654F;    // equivalent to [NSNumber numberWithFloat:3.141592654F]57      NSNumber *piDouble = @3.1415926535;   // equivalent to [NSNumber numberWithDouble:3.1415926535]58 59      // BOOL literals.60      NSNumber *yesNumber = @YES;           // equivalent to [NSNumber numberWithBool:YES]61      NSNumber *noNumber = @NO;             // equivalent to [NSNumber numberWithBool:NO]62 63    #ifdef __cplusplus64      NSNumber *trueNumber = @true;         // equivalent to [NSNumber numberWithBool:(BOOL)true]65      NSNumber *falseNumber = @false;       // equivalent to [NSNumber numberWithBool:(BOOL)false]66    #endif67    }68 69Discussion70----------71 72NSNumber literals only support literal scalar values after the ``'@'``.73Consequently, ``@INT_MAX`` works, but ``@INT_MIN`` does not, because74they are defined like this:75 76.. code-block:: objc77 78    #define INT_MAX   2147483647  /* max value for an int */79    #define INT_MIN   (-2147483647-1) /* min value for an int */80 81The definition of ``INT_MIN`` is not a simple literal, but a82parenthesized expression. Parenthesized expressions are supported using83the `boxed expression <#objc_boxed_expressions>`_ syntax, which is84described in the next section.85 86Because ``NSNumber`` does not currently support wrapping ``long double``87values, the use of a ``long double NSNumber`` literal (e.g.88``@123.23L``) will be rejected by the compiler.89 90Previously, the ``BOOL`` type was simply a typedef for ``signed char``,91and ``YES`` and ``NO`` were macros that expand to ``(BOOL)1`` and92``(BOOL)0`` respectively. To support ``@YES`` and ``@NO`` expressions,93these macros are now defined using new language keywords in94``<objc/objc.h>``:95 96.. code-block:: objc97 98    #if __has_feature(objc_bool)99    #define YES             __objc_yes100    #define NO              __objc_no101    #else102    #define YES             ((BOOL)1)103    #define NO              ((BOOL)0)104    #endif105 106The compiler implicitly converts ``__objc_yes`` and ``__objc_no`` to107``(BOOL)1`` and ``(BOOL)0``. The keywords are used to disambiguate108``BOOL`` and integer literals.109 110Objective-C++ also supports ``@true`` and ``@false`` expressions, which111are equivalent to ``@YES`` and ``@NO``.112 113Boxed Expressions114=================115 116Objective-C provides a new syntax for boxing C expressions:117 118.. code-block:: objc119 120    @( <expression> )121 122Expressions of scalar (numeric, enumerated, BOOL), C string pointer123and some C structures (via NSValue) are supported:124 125.. code-block:: objc126 127    // numbers.128    NSNumber *smallestInt = @(-INT_MAX - 1);  // [NSNumber numberWithInt:(-INT_MAX - 1)]129    NSNumber *piOverTwo = @(M_PI / 2);        // [NSNumber numberWithDouble:(M_PI / 2)]130 131    // enumerated types.132    typedef enum { Red, Green, Blue } Color;133    NSNumber *favoriteColor = @(Green);       // [NSNumber numberWithInt:((int)Green)]134 135    // strings.136    NSString *path = @(getenv("PATH"));       // [NSString stringWithUTF8String:(getenv("PATH"))]137    NSArray *pathComponents = [path componentsSeparatedByString:@":"];138 139    // structs.140    NSValue *center = @(view.center);         // Point p = view.center;141                                              // [NSValue valueWithBytes:&p objCType:@encode(Point)];142    NSValue *frame = @(view.frame);           // Rect r = view.frame;143                                              // [NSValue valueWithBytes:&r objCType:@encode(Rect)];144 145Boxed Enums146-----------147 148Cocoa frameworks frequently define constant values using *enums.*149Although enum values are integral, they may not be used directly as150boxed literals (this avoids conflicts with future ``'@'``-prefixed151Objective-C keywords). Instead, an enum value must be placed inside a152boxed expression. The following example demonstrates configuring an153``AVAudioRecorder`` using a dictionary that contains a boxed enumeration154value:155 156.. code-block:: objc157 158    enum {159      AVAudioQualityMin = 0,160      AVAudioQualityLow = 0x20,161      AVAudioQualityMedium = 0x40,162      AVAudioQualityHigh = 0x60,163      AVAudioQualityMax = 0x7F164    };165 166    - (AVAudioRecorder *)recordToFile:(NSURL *)fileURL {167      NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) };168      return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL];169    }170 171The expression ``@(AVAudioQualityMax)`` converts ``AVAudioQualityMax``172to an integer type, and boxes the value accordingly. If the enum has a173:ref:`fixed underlying type <objc-fixed-enum>` as in:174 175.. code-block:: objc176 177    typedef enum : unsigned char { Red, Green, Blue } Color;178    NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:]179 180then the fixed underlying type will be used to select the correct181``NSNumber`` creation method.182 183Boxing a value of enum type will result in a ``NSNumber`` pointer with a184creation method according to the underlying type of the enum, which can185be a :ref:`fixed underlying type <objc-fixed-enum>`186or a compiler-defined integer type capable of representing the values of187all the members of the enumeration:188 189.. code-block:: objc190 191    typedef enum : unsigned char { Red, Green, Blue } Color;192    Color col = Red;193    NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:]194 195Boxed C Strings196---------------197 198A C string literal prefixed by the ``'@'`` token denotes an ``NSString``199literal in the same way a numeric literal prefixed by the ``'@'`` token200denotes an ``NSNumber`` literal. When the type of the parenthesized201expression is ``(char *)`` or ``(const char *)``, the result of the202boxed expression is a pointer to an ``NSString`` object containing203equivalent character data, which is assumed to be '\\0'-terminated and204UTF-8 encoded. The following example converts C-style command line205arguments into ``NSString`` objects.206 207.. code-block:: objc208 209    // Partition command line arguments into positional and option arguments.210    NSMutableArray *args = [NSMutableArray new];211    NSMutableDictionary *options = [NSMutableDictionary new];212    while (--argc) {213        const char *arg = *++argv;214        if (strncmp(arg, "--", 2) == 0) {215            options[@(arg + 2)] = @(*++argv);   // --key value216        } else {217            [args addObject:@(arg)];            // positional argument218        }219    }220 221As with all C pointers, character pointer expressions can involve222arbitrary pointer arithmetic, therefore programmers must ensure that the223character data is valid. Passing ``NULL`` as the character pointer will224raise an exception at runtime. When possible, the compiler will reject225``NULL`` character pointers used in boxed expressions.226 227Boxed C Structures228------------------229 230Boxed expressions support construction of NSValue objects.231It said that C structures can be used, the only requirement is:232structure should be marked with ``objc_boxable`` attribute.233To support older version of frameworks and/or third-party libraries234you may need to add the attribute via ``typedef``.235 236.. code-block:: objc237 238    struct __attribute__((objc_boxable)) Point {239        // ...240    };241 242    typedef struct __attribute__((objc_boxable)) _Size {243        // ...244    } Size;245 246    typedef struct _Rect {247        // ...248    } Rect;249 250    struct Point p;251    NSValue *point = @(p);          // ok252    Size s;253    NSValue *size = @(s);           // ok254 255    Rect r;256    NSValue *bad_rect = @(r);       // error257 258    typedef struct __attribute__((objc_boxable)) _Rect Rect;259 260    NSValue *good_rect = @(r);      // ok261 262 263Container Literals264==================265 266Objective-C now supports a new expression syntax for creating immutable267array and dictionary container objects.268 269Examples270--------271 272Immutable array expression:273 274.. code-block:: objc275 276    NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];277 278This creates an ``NSArray`` with 3 elements. The comma-separated279sub-expressions of an array literal can be any Objective-C object280pointer typed expression.281 282Immutable dictionary expression:283 284.. code-block:: objc285 286    NSDictionary *dictionary = @{287        @"name" : NSUserName(),288        @"date" : [NSDate date],289        @"processInfo" : [NSProcessInfo processInfo]290    };291 292This creates an ``NSDictionary`` with 3 key/value pairs. Value293sub-expressions of a dictionary literal must be Objective-C object294pointer typed, as in array literals. Key sub-expressions must be of an295Objective-C object pointer type that implements the296``<NSCopying>`` protocol.297 298Discussion299----------300 301Neither keys nor values can have the value ``nil`` in containers. If the302compiler can prove that a key or value is ``nil`` at compile time, then303a warning will be emitted. Otherwise, a runtime error will occur.304 305Using array and dictionary literals is safer than the variadic creation306forms commonly in use today. Array literal expressions expand to calls307to ``+[NSArray arrayWithObjects:count:]``, which validates that all308objects are non-``nil``. The variadic form,309``+[NSArray arrayWithObjects:]`` uses ``nil`` as an argument list310terminator, which can lead to malformed array objects. Dictionary311literals are similarly created with312``+[NSDictionary dictionaryWithObjects:forKeys:count:]`` which validates313all objects and keys, unlike314``+[NSDictionary dictionaryWithObjectsAndKeys:]`` which also uses a315``nil`` parameter as an argument list terminator.316 317Object Subscripting318===================319 320Objective-C object pointer values can now be used with C's subscripting321operator.322 323Examples324--------325 326The following code demonstrates the use of object subscripting syntax327with ``NSMutableArray`` and ``NSMutableDictionary`` objects:328 329.. code-block:: objc330 331    NSMutableArray *array = ...;332    NSUInteger idx = ...;333    id newObject = ...;334    id oldObject = array[idx];335    array[idx] = newObject;         // replace oldObject with newObject336 337    NSMutableDictionary *dictionary = ...;338    NSString *key = ...;339    oldObject = dictionary[key];340    dictionary[key] = newObject;    // replace oldObject with newObject341 342The next section explains how subscripting expressions map to accessor343methods.344 345Subscripting Methods346--------------------347 348Objective-C supports two kinds of subscript expressions: *array-style*349subscript expressions use integer typed subscripts; *dictionary-style*350subscript expressions use Objective-C object pointer typed subscripts.351Each type of subscript expression is mapped to a message send using a352predefined selector. The advantage of this design is flexibility: class353designers are free to introduce subscripting by declaring methods or by354adopting protocols. Moreover, because the method names are selected by355the type of the subscript, an object can be subscripted using both array356and dictionary styles.357 358Array-Style Subscripting359^^^^^^^^^^^^^^^^^^^^^^^^360 361When the subscript operand has an integral type, the expression is362rewritten to use one of two different selectors, depending on whether363the element is being read or written. When an expression reads an364element using an integral index, as in the following example:365 366.. code-block:: objc367 368    NSUInteger idx = ...;369    id value = object[idx];370 371it is translated into a call to ``objectAtIndexedSubscript:``372 373.. code-block:: objc374 375    id value = [object objectAtIndexedSubscript:idx];376 377When an expression writes an element using an integral index:378 379.. code-block:: objc380 381    object[idx] = newValue;382 383it is translated to a call to ``setObject:atIndexedSubscript:``384 385.. code-block:: objc386 387    [object setObject:newValue atIndexedSubscript:idx];388 389These message sends are then type-checked and performed just like390explicit message sends. The method used for objectAtIndexedSubscript:391must be declared with an argument of integral type and a return value of392some Objective-C object pointer type. The method used for393setObject:atIndexedSubscript: must be declared with its first argument394having some Objective-C pointer type and its second argument having395integral type.396 397The meaning of indexes is left up to the declaring class. The compiler398will coerce the index to the appropriate argument type of the method it399uses for type-checking. For an instance of ``NSArray``, reading an400element using an index outside the range ``[0, array.count)`` will raise401an exception. For an instance of ``NSMutableArray``, assigning to an402element using an index within this range will replace that element, but403assigning to an element using an index outside this range will raise an404exception; no syntax is provided for inserting, appending, or removing405elements for mutable arrays.406 407A class need not declare both methods in order to take advantage of this408language feature. For example, the class ``NSArray`` declares only409``objectAtIndexedSubscript:``, so that assignments to elements will fail410to type-check; moreover, its subclass ``NSMutableArray`` declares411``setObject:atIndexedSubscript:``.412 413Dictionary-Style Subscripting414^^^^^^^^^^^^^^^^^^^^^^^^^^^^^415 416When the subscript operand has an Objective-C object pointer type, the417expression is rewritten to use one of two different selectors, depending418on whether the element is being read from or written to. When an419expression reads an element using an Objective-C object pointer420subscript operand, as in the following example:421 422.. code-block:: objc423 424    id key = ...;425    id value = object[key];426 427it is translated into a call to the ``objectForKeyedSubscript:`` method:428 429.. code-block:: objc430 431    id value = [object objectForKeyedSubscript:key];432 433When an expression writes an element using an Objective-C object pointer434subscript:435 436.. code-block:: objc437 438    object[key] = newValue;439 440it is translated to a call to ``setObject:forKeyedSubscript:``441 442.. code-block:: objc443 444    [object setObject:newValue forKeyedSubscript:key];445 446The behavior of ``setObject:forKeyedSubscript:`` is class-specific; but447in general it should replace an existing value if one is already448associated with a key, otherwise it should add a new value for the key.449No syntax is provided for removing elements from mutable dictionaries.450 451Discussion452----------453 454An Objective-C subscript expression occurs when the base operand of the455C subscript operator has an Objective-C object pointer type. Since this456potentially collides with pointer arithmetic on the value, these457expressions are only supported under the modern Objective-C runtime,458which categorically forbids such arithmetic.459 460Currently, only subscripts of integral or Objective-C object pointer461type are supported. In C++, a class type can be used if it has a single462conversion function to an integral or Objective-C pointer type, in which463case that conversion is applied and analysis continues as appropriate.464Otherwise, the expression is ill-formed.465 466An Objective-C object subscript expression is always an l-value. If the467expression appears on the left-hand side of a simple assignment operator468(=), the element is written as described below. If the expression469appears on the left-hand side of a compound assignment operator (e.g.470+=), the program is ill-formed, because the result of reading an element471is always an Objective-C object pointer and no binary operators are472legal on such pointers. If the expression appears in any other position,473the element is read as described below. It is an error to take the474address of a subscript expression, or (in C++) to bind a reference to475it.476 477Programs can use object subscripting with Objective-C object pointers of478type ``id``. Normal dynamic message send rules apply; the compiler must479see *some* declaration of the subscripting methods, and will pick the480declaration seen first.481 482Caveats483=======484 485Objects created using the literal or boxed expression syntax are not486guaranteed to be uniqued by the runtime, but nor are they guaranteed to487be newly-allocated. As such, the result of performing direct comparisons488against the location of an object literal (using ``==``, ``!=``, ``<``,489``<=``, ``>``, or ``>=``) is not well-defined. This is usually a simple490mistake in code that intended to call the ``isEqual:`` method (or the491``compare:`` method).492 493This caveat applies to compile-time string literals as well.494Historically, string literals (using the ``@"..."`` syntax) have been495uniqued across translation units during linking. This is an496implementation detail of the compiler and should not be relied upon. If497you are using such code, please use global string constants instead498(``NSString * const MyConst = @"..."``) or use ``isEqual:``.499 500Grammar Additions501=================502 503To support the new syntax described above, the Objective-C504``@``-expression grammar has the following new productions:505 506::507 508    objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal)509                       ;510 511    object-literal : ('+' | '-')? numeric-constant512                   | character-constant513                   | boolean-constant514                   | array-literal515                   | dictionary-literal516                   ;517 518    boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false'  /* boolean keywords. */519                     ;520 521    array-literal : '[' assignment-expression-list ']'522                  ;523 524    assignment-expression-list : assignment-expression (',' assignment-expression-list)?525                               | /* empty */526                               ;527 528    dictionary-literal : '{' key-value-list '}'529                       ;530 531    key-value-list : key-value-pair (',' key-value-list)?532                   | /* empty */533                   ;534 535    key-value-pair : assignment-expression ':' assignment-expression536                   ;537 538Note: ``@true`` and ``@false`` are only supported in Objective-C++.539 540Availability Checks541===================542 543Programs test for the new features by using clang's \_\_has\_feature544checks. Here are examples of their use:545 546.. code-block:: objc547 548    #if __has_feature(objc_array_literals)549        // new way.550        NSArray *elements = @[ @"H", @"He", @"O", @"C" ];551    #else552        // old way (equivalent).553        id objects[] = { @"H", @"He", @"O", @"C" };554        NSArray *elements = [NSArray arrayWithObjects:objects count:4];555    #endif556 557    #if __has_feature(objc_dictionary_literals)558        // new way.559        NSDictionary *masses = @{ @"H" : @1.0078,  @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 };560    #else561        // old way (equivalent).562        id keys[] = { @"H", @"He", @"O", @"C" };563        id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026],564                        [NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] };565        NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4];566    #endif567 568    #if __has_feature(objc_subscripting)569        NSUInteger i, count = elements.count;570        for (i = 0; i < count; ++i) {571            NSString *element = elements[i];572            NSNumber *mass = masses[element];573            NSLog(@"the mass of %@ is %@", element, mass);574        }575    #else576        NSUInteger i, count = [elements count];577        for (i = 0; i < count; ++i) {578            NSString *element = [elements objectAtIndex:i];579            NSNumber *mass = [masses objectForKey:element];580            NSLog(@"the mass of %@ is %@", element, mass);581        }582    #endif583 584    #if __has_attribute(objc_boxable)585        typedef struct __attribute__((objc_boxable)) _Rect Rect;586    #endif587 588    #if __has_feature(objc_boxed_nsvalue_expressions)589        CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"];590        animation.fromValue = @(layer.position);591        animation.toValue = @(newPosition);592        [layer addAnimation:animation forKey:@"move"];593    #else594        CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"];595        animation.fromValue = [NSValue valueWithCGPoint:layer.position];596        animation.toValue = [NSValue valueWithCGPoint:newPosition];597        [layer addAnimation:animation forKey:@"move"];598    #endif599 600Code can use also ``__has_feature(objc_bool)`` to check for the601availability of numeric literals support. This checks for the new602``__objc_yes / __objc_no`` keywords, which enable the use of603``@YES / @NO`` literals.604 605To check whether boxed expressions are supported, use606``__has_feature(objc_boxed_expressions)`` feature macro.607