Home | History | Annotate | Download | only in docs
      1 ====================
      2 Objective-C Literals
      3 ====================
      4 
      5 Introduction
      6 ============
      7 
      8 Three new features were introduced into clang at the same time:
      9 *NSNumber Literals* provide a syntax for creating ``NSNumber`` from
     10 scalar literal expressions; *Collection Literals* provide a short-hand
     11 for creating arrays and dictionaries; *Object Subscripting* provides a
     12 way to use subscripting with Objective-C objects. Users of Apple
     13 compiler releases can use these features starting with the Apple LLVM
     14 Compiler 4.0. Users of open-source LLVM.org compiler releases can use
     15 these features starting with clang v3.1.
     16 
     17 These language additions simplify common Objective-C programming
     18 patterns, make programs more concise, and improve the safety of
     19 container creation.
     20 
     21 This document describes how the features are implemented in clang, and
     22 how to use them in your own programs.
     23 
     24 NSNumber Literals
     25 =================
     26 
     27 The framework class ``NSNumber`` is used to wrap scalar values inside
     28 objects: signed and unsigned integers (``char``, ``short``, ``int``,
     29 ``long``, ``long long``), floating point numbers (``float``,
     30 ``double``), and boolean values (``BOOL``, C++ ``bool``). Scalar values
     31 wrapped in objects are also known as *boxed* values.
     32 
     33 In Objective-C, any character, numeric or boolean literal prefixed with
     34 the ``'@'`` character will evaluate to a pointer to an ``NSNumber``
     35 object initialized with that value. C's type suffixes may be used to
     36 control the size of numeric literals.
     37 
     38 Examples
     39 --------
     40 
     41 The following program illustrates the rules for ``NSNumber`` literals:
     42 
     43 .. code-block:: objc
     44 
     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 __cplusplus
     64       NSNumber *trueNumber = @true;         // equivalent to [NSNumber numberWithBool:(BOOL)true]
     65       NSNumber *falseNumber = @false;       // equivalent to [NSNumber numberWithBool:(BOOL)false]
     66     #endif
     67     }
     68 
     69 Discussion
     70 ----------
     71 
     72 NSNumber literals only support literal scalar values after the ``'@'``.
     73 Consequently, ``@INT_MAX`` works, but ``@INT_MIN`` does not, because
     74 they are defined like this:
     75 
     76 .. code-block:: objc
     77 
     78     #define INT_MAX   2147483647  /* max value for an int */
     79     #define INT_MIN   (-2147483647-1) /* min value for an int */
     80 
     81 The definition of ``INT_MIN`` is not a simple literal, but a
     82 parenthesized expression. Parenthesized expressions are supported using
     83 the `boxed expression <#objc_boxed_expressions>`_ syntax, which is
     84 described in the next section.
     85 
     86 Because ``NSNumber`` does not currently support wrapping ``long double``
     87 values, the use of a ``long double NSNumber`` literal (e.g.
     88 ``@123.23L``) will be rejected by the compiler.
     89 
     90 Previously, the ``BOOL`` type was simply a typedef for ``signed char``,
     91 and ``YES`` and ``NO`` were macros that expand to ``(BOOL)1`` and
     92 ``(BOOL)0`` respectively. To support ``@YES`` and ``@NO`` expressions,
     93 these macros are now defined using new language keywords in
     94 ``<objc/objc.h>``:
     95 
     96 .. code-block:: objc
     97 
     98     #if __has_feature(objc_bool)
     99     #define YES             __objc_yes
    100     #define NO              __objc_no
    101     #else
    102     #define YES             ((BOOL)1)
    103     #define NO              ((BOOL)0)
    104     #endif
    105 
    106 The compiler implicitly converts ``__objc_yes`` and ``__objc_no`` to
    107 ``(BOOL)1`` and ``(BOOL)0``. The keywords are used to disambiguate
    108 ``BOOL`` and integer literals.
    109 
    110 Objective-C++ also supports ``@true`` and ``@false`` expressions, which
    111 are equivalent to ``@YES`` and ``@NO``.
    112 
    113 Boxed Expressions
    114 =================
    115 
    116 Objective-C provides a new syntax for boxing C expressions:
    117 
    118 .. code-block:: objc
    119 
    120     @( <expression> )
    121 
    122 Expressions of scalar (numeric, enumerated, BOOL), C string pointer
    123 and some C structures (via NSValue) are supported:
    124 
    125 .. code-block:: objc
    126 
    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 
    145 Boxed Enums
    146 -----------
    147 
    148 Cocoa frameworks frequently define constant values using *enums.*
    149 Although enum values are integral, they may not be used directly as
    150 boxed literals (this avoids conflicts with future ``'@'``-prefixed
    151 Objective-C keywords). Instead, an enum value must be placed inside a
    152 boxed expression. The following example demonstrates configuring an
    153 ``AVAudioRecorder`` using a dictionary that contains a boxed enumeration
    154 value:
    155 
    156 .. code-block:: objc
    157 
    158     enum {
    159       AVAudioQualityMin = 0,
    160       AVAudioQualityLow = 0x20,
    161       AVAudioQualityMedium = 0x40,
    162       AVAudioQualityHigh = 0x60,
    163       AVAudioQualityMax = 0x7F
    164     };
    165 
    166     - (AVAudioRecorder *)recordToFile:(NSURL *)fileURL {
    167       NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) };
    168       return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL];
    169     }
    170 
    171 The expression ``@(AVAudioQualityMax)`` converts ``AVAudioQualityMax``
    172 to an integer type, and boxes the value accordingly. If the enum has a
    173 :ref:`fixed underlying type <objc-fixed-enum>` as in:
    174 
    175 .. code-block:: objc
    176 
    177     typedef enum : unsigned char { Red, Green, Blue } Color;
    178     NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:]
    179 
    180 then the fixed underlying type will be used to select the correct
    181 ``NSNumber`` creation method.
    182 
    183 Boxing a value of enum type will result in a ``NSNumber`` pointer with a
    184 creation method according to the underlying type of the enum, which can
    185 be a :ref:`fixed underlying type <objc-fixed-enum>`
    186 or a compiler-defined integer type capable of representing the values of
    187 all the members of the enumeration:
    188 
    189 .. code-block:: objc
    190 
    191     typedef enum : unsigned char { Red, Green, Blue } Color;
    192     Color col = Red;
    193     NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:]
    194 
    195 Boxed C Strings
    196 ---------------
    197 
    198 A C string literal prefixed by the ``'@'`` token denotes an ``NSString``
    199 literal in the same way a numeric literal prefixed by the ``'@'`` token
    200 denotes an ``NSNumber`` literal. When the type of the parenthesized
    201 expression is ``(char *)`` or ``(const char *)``, the result of the
    202 boxed expression is a pointer to an ``NSString`` object containing
    203 equivalent character data, which is assumed to be '\\0'-terminated and
    204 UTF-8 encoded. The following example converts C-style command line
    205 arguments into ``NSString`` objects.
    206 
    207 .. code-block:: objc
    208 
    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 value
    216         } else {
    217             [args addObject:@(arg)];            // positional argument
    218         }
    219     }
    220 
    221 As with all C pointers, character pointer expressions can involve
    222 arbitrary pointer arithmetic, therefore programmers must ensure that the
    223 character data is valid. Passing ``NULL`` as the character pointer will
    224 raise an exception at runtime. When possible, the compiler will reject
    225 ``NULL`` character pointers used in boxed expressions.
    226 
    227 Boxed C Structures
    228 ------------------
    229 
    230 Boxed expressions support construction of NSValue objects.
    231 It said that C structures can be used, the only requirement is:
    232 structure should be marked with ``objc_boxable`` attribute.
    233 To support older version of frameworks and/or third-party libraries
    234 you may need to add the attribute via ``typedef``.
    235 
    236 .. code-block:: objc
    237 
    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);          // ok
    252     Size s;
    253     NSValue *size = @(s);           // ok
    254 
    255     Rect r;
    256     NSValue *bad_rect = @(r);       // error
    257 
    258     typedef struct __attribute__((objc_boxable)) _Rect Rect;
    259 
    260     NSValue *good_rect = @(r);      // ok
    261 
    262 
    263 Container Literals
    264 ==================
    265 
    266 Objective-C now supports a new expression syntax for creating immutable
    267 array and dictionary container objects.
    268 
    269 Examples
    270 --------
    271 
    272 Immutable array expression:
    273 
    274 .. code-block:: objc
    275 
    276     NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
    277 
    278 This creates an ``NSArray`` with 3 elements. The comma-separated
    279 sub-expressions of an array literal can be any Objective-C object
    280 pointer typed expression.
    281 
    282 Immutable dictionary expression:
    283 
    284 .. code-block:: objc
    285 
    286     NSDictionary *dictionary = @{
    287         @"name" : NSUserName(),
    288         @"date" : [NSDate date],
    289         @"processInfo" : [NSProcessInfo processInfo]
    290     };
    291 
    292 This creates an ``NSDictionary`` with 3 key/value pairs. Value
    293 sub-expressions of a dictionary literal must be Objective-C object
    294 pointer typed, as in array literals. Key sub-expressions must be of an
    295 Objective-C object pointer type that implements the
    296 ``<NSCopying>`` protocol.
    297 
    298 Discussion
    299 ----------
    300 
    301 Neither keys nor values can have the value ``nil`` in containers. If the
    302 compiler can prove that a key or value is ``nil`` at compile time, then
    303 a warning will be emitted. Otherwise, a runtime error will occur.
    304 
    305 Using array and dictionary literals is safer than the variadic creation
    306 forms commonly in use today. Array literal expressions expand to calls
    307 to ``+[NSArray arrayWithObjects:count:]``, which validates that all
    308 objects are non-``nil``. The variadic form,
    309 ``+[NSArray arrayWithObjects:]`` uses ``nil`` as an argument list
    310 terminator, which can lead to malformed array objects. Dictionary
    311 literals are similarly created with
    312 ``+[NSDictionary dictionaryWithObjects:forKeys:count:]`` which validates
    313 all objects and keys, unlike
    314 ``+[NSDictionary dictionaryWithObjectsAndKeys:]`` which also uses a
    315 ``nil`` parameter as an argument list terminator.
    316 
    317 Object Subscripting
    318 ===================
    319 
    320 Objective-C object pointer values can now be used with C's subscripting
    321 operator.
    322 
    323 Examples
    324 --------
    325 
    326 The following code demonstrates the use of object subscripting syntax
    327 with ``NSMutableArray`` and ``NSMutableDictionary`` objects:
    328 
    329 .. code-block:: objc
    330 
    331     NSMutableArray *array = ...;
    332     NSUInteger idx = ...;
    333     id newObject = ...;
    334     id oldObject = array[idx];
    335     array[idx] = newObject;         // replace oldObject with newObject
    336 
    337     NSMutableDictionary *dictionary = ...;
    338     NSString *key = ...;
    339     oldObject = dictionary[key];
    340     dictionary[key] = newObject;    // replace oldObject with newObject
    341 
    342 The next section explains how subscripting expressions map to accessor
    343 methods.
    344 
    345 Subscripting Methods
    346 --------------------
    347 
    348 Objective-C supports two kinds of subscript expressions: *array-style*
    349 subscript expressions use integer typed subscripts; *dictionary-style*
    350 subscript expressions use Objective-C object pointer typed subscripts.
    351 Each type of subscript expression is mapped to a message send using a
    352 predefined selector. The advantage of this design is flexibility: class
    353 designers are free to introduce subscripting by declaring methods or by
    354 adopting protocols. Moreover, because the method names are selected by
    355 the type of the subscript, an object can be subscripted using both array
    356 and dictionary styles.
    357 
    358 Array-Style Subscripting
    359 ^^^^^^^^^^^^^^^^^^^^^^^^
    360 
    361 When the subscript operand has an integral type, the expression is
    362 rewritten to use one of two different selectors, depending on whether
    363 the element is being read or written. When an expression reads an
    364 element using an integral index, as in the following example:
    365 
    366 .. code-block:: objc
    367 
    368     NSUInteger idx = ...;
    369     id value = object[idx];
    370 
    371 it is translated into a call to ``objectAtIndexedSubscript:``
    372 
    373 .. code-block:: objc
    374 
    375     id value = [object objectAtIndexedSubscript:idx];
    376 
    377 When an expression writes an element using an integral index:
    378 
    379 .. code-block:: objc
    380 
    381     object[idx] = newValue;
    382 
    383 it is translated to a call to ``setObject:atIndexedSubscript:``
    384 
    385 .. code-block:: objc
    386 
    387     [object setObject:newValue atIndexedSubscript:idx];
    388 
    389 These message sends are then type-checked and performed just like
    390 explicit message sends. The method used for objectAtIndexedSubscript:
    391 must be declared with an argument of integral type and a return value of
    392 some Objective-C object pointer type. The method used for
    393 setObject:atIndexedSubscript: must be declared with its first argument
    394 having some Objective-C pointer type and its second argument having
    395 integral type.
    396 
    397 The meaning of indexes is left up to the declaring class. The compiler
    398 will coerce the index to the appropriate argument type of the method it
    399 uses for type-checking. For an instance of ``NSArray``, reading an
    400 element using an index outside the range ``[0, array.count)`` will raise
    401 an exception. For an instance of ``NSMutableArray``, assigning to an
    402 element using an index within this range will replace that element, but
    403 assigning to an element using an index outside this range will raise an
    404 exception; no syntax is provided for inserting, appending, or removing
    405 elements for mutable arrays.
    406 
    407 A class need not declare both methods in order to take advantage of this
    408 language feature. For example, the class ``NSArray`` declares only
    409 ``objectAtIndexedSubscript:``, so that assignments to elements will fail
    410 to type-check; moreover, its subclass ``NSMutableArray`` declares
    411 ``setObject:atIndexedSubscript:``.
    412 
    413 Dictionary-Style Subscripting
    414 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    415 
    416 When the subscript operand has an Objective-C object pointer type, the
    417 expression is rewritten to use one of two different selectors, depending
    418 on whether the element is being read from or written to. When an
    419 expression reads an element using an Objective-C object pointer
    420 subscript operand, as in the following example:
    421 
    422 .. code-block:: objc
    423 
    424     id key = ...;
    425     id value = object[key];
    426 
    427 it is translated into a call to the ``objectForKeyedSubscript:`` method:
    428 
    429 .. code-block:: objc
    430 
    431     id value = [object objectForKeyedSubscript:key];
    432 
    433 When an expression writes an element using an Objective-C object pointer
    434 subscript:
    435 
    436 .. code-block:: objc
    437 
    438     object[key] = newValue;
    439 
    440 it is translated to a call to ``setObject:forKeyedSubscript:``
    441 
    442 .. code-block:: objc
    443 
    444     [object setObject:newValue forKeyedSubscript:key];
    445 
    446 The behavior of ``setObject:forKeyedSubscript:`` is class-specific; but
    447 in general it should replace an existing value if one is already
    448 associated with a key, otherwise it should add a new value for the key.
    449 No syntax is provided for removing elements from mutable dictionaries.
    450 
    451 Discussion
    452 ----------
    453 
    454 An Objective-C subscript expression occurs when the base operand of the
    455 C subscript operator has an Objective-C object pointer type. Since this
    456 potentially collides with pointer arithmetic on the value, these
    457 expressions are only supported under the modern Objective-C runtime,
    458 which categorically forbids such arithmetic.
    459 
    460 Currently, only subscripts of integral or Objective-C object pointer
    461 type are supported. In C++, a class type can be used if it has a single
    462 conversion function to an integral or Objective-C pointer type, in which
    463 case that conversion is applied and analysis continues as appropriate.
    464 Otherwise, the expression is ill-formed.
    465 
    466 An Objective-C object subscript expression is always an l-value. If the
    467 expression appears on the left-hand side of a simple assignment operator
    468 (=), the element is written as described below. If the expression
    469 appears on the left-hand side of a compound assignment operator (e.g.
    470 +=), the program is ill-formed, because the result of reading an element
    471 is always an Objective-C object pointer and no binary operators are
    472 legal on such pointers. If the expression appears in any other position,
    473 the element is read as described below. It is an error to take the
    474 address of a subscript expression, or (in C++) to bind a reference to
    475 it.
    476 
    477 Programs can use object subscripting with Objective-C object pointers of
    478 type ``id``. Normal dynamic message send rules apply; the compiler must
    479 see *some* declaration of the subscripting methods, and will pick the
    480 declaration seen first.
    481 
    482 Caveats
    483 =======
    484 
    485 Objects created using the literal or boxed expression syntax are not
    486 guaranteed to be uniqued by the runtime, but nor are they guaranteed to
    487 be newly-allocated. As such, the result of performing direct comparisons
    488 against the location of an object literal (using ``==``, ``!=``, ``<``,
    489 ``<=``, ``>``, or ``>=``) is not well-defined. This is usually a simple
    490 mistake in code that intended to call the ``isEqual:`` method (or the
    491 ``compare:`` method).
    492 
    493 This caveat applies to compile-time string literals as well.
    494 Historically, string literals (using the ``@"..."`` syntax) have been
    495 uniqued across translation units during linking. This is an
    496 implementation detail of the compiler and should not be relied upon. If
    497 you are using such code, please use global string constants instead
    498 (``NSString * const MyConst = @"..."``) or use ``isEqual:``.
    499 
    500 Grammar Additions
    501 =================
    502 
    503 To support the new syntax described above, the Objective-C
    504 ``@``-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-constant
    512                    | character-constant
    513                    | boolean-constant
    514                    | array-literal
    515                    | dictionary-literal
    516                    ;
    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-expression
    536                    ;
    537 
    538 Note: ``@true`` and ``@false`` are only supported in Objective-C++.
    539 
    540 Availability Checks
    541 ===================
    542 
    543 Programs test for the new features by using clang's \_\_has\_feature
    544 checks. Here are examples of their use:
    545 
    546 .. code-block:: objc
    547 
    548     #if __has_feature(objc_array_literals)
    549         // new way.
    550         NSArray *elements = @[ @"H", @"He", @"O", @"C" ];
    551     #else
    552         // old way (equivalent).
    553         id objects[] = { @"H", @"He", @"O", @"C" };
    554         NSArray *elements = [NSArray arrayWithObjects:objects count:4];
    555     #endif
    556 
    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     #else
    561         // 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     #endif
    567 
    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     #else
    576         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     #endif
    583 
    584     #if __has_attribute(objc_boxable)
    585         typedef struct __attribute__((objc_boxable)) _Rect Rect;
    586     #endif
    587 
    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     #else
    594         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     #endif
    599 
    600 Code can use also ``__has_feature(objc_bool)`` to check for the
    601 availability of numeric literals support. This checks for the new
    602 ``__objc_yes / __objc_no`` keywords, which enable the use of
    603 ``@YES / @NO`` literals.
    604 
    605 To check whether boxed expressions are supported, use
    606 ``__has_feature(objc_boxed_expressions)`` feature macro.
    607