Objective-C in,out,inout,byref,byval, .. and so on. What are they?

I discovered something unfamiliar while reading Objective-C manual for @encoding.

Table 6-2  Objective-C method encodings
Code Meaning
r    const
n    in
N    inout
o    out
O    bycopy
R    byref
V    oneway

The only thing I know is oneway. What are the others?


Solution 1:

Those are annotations for method parameters and return values which were used by Distributed Objects. I say were because apparently there’s no sign of them in Apple’s documentation any longer. There used to be a Remote Messaging section in The Objective-C Programming Language document, which is still referenced by the Distributed Objects Programming Topics document.

  • in: argument is an input argument only and won’t be referenced later
  • out: argument is an output argument only, used to return a value by reference
  • inout: argument is both an input and output argument
  • const: the (pointer) argument is constant
  • bycopy: instead of using a proxy/NSDistantObject, pass or return a copy of the object
  • byref: use a proxy object (default)

Solution 2:

Beyond Distributed Objects, one of these annotations appears to be used by ARC. I came across the following in clang's description of passing to an out parameter by writeback:

If the parameter is not an Objective-C method parameter marked out, then *p is read, and the result is written into the temporary with primitive semantics.

This has to do with methods like - (BOOL)executeWithError:(out NSError **)error.

Ignoring the out keyword, ARC has a well-defined behavior of treating by-reference object passing as __autoreleasing, so ARC treats the error parameter as having a type of NSError * __autoreleasing *. If you use an otherwise qualified variable, ARC will add a temporary autoreleasing variable pass into the function (for coherence):

Original code

NSError *error;
[obj executeWithError:&error];

Pseudotransformed code

NSError * __strong error;
NSError * __autoreleasing temp;
temp = error;
[obj executeWithError:&temp];
error = temp;

With the above code, the line temp = error would be unnecessary if we could somehow know that temp will never be read. This is where the out annotation comes into play. Per the quoted description if out is missing the compiler must add the line temp = error but if it does contain out it can exclude the line and make the code just a little bit smaller/faster. With out the transformed code becomes:

NSError * __strong error;
NSError * __autoreleasing temp;
[obj executeWithError:&temp];
error = temp;

Of course, if you're that worried about binary size and speed, you should just code the following:

NSError * __autoreleasing error;
[obj executeWithError:&error];

It is entirely possible that these annotations are used other places throughout the compiler and runtime, and may be used in more places in the future. Personally, I like using out as a hint to other developers that I'm not going to read the value.