What does the const specifier do, before a pointer to object? - objective-c

If I have a C-string like this:
const char* str= "hello";
I know well that I can't change any character of the string because the pointer is const.
But if I have this:
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
I can still mutate the object state using it's methods.
If the pointer is to a NSMutableString, I'm still able to mutate it.
Then what does the const stand for?

In that method declaration, location is a pointer to a constant CLLocation. But when you send a message to the location object, the const-ness is not preserved; the method that handles the message sees self as a non-const object. (Note that this is different than C++, which supports const member functions where this is a pointer to a constant object.)
So the const in that declaration is not particularly useful. Perhaps it was written by someone used to the C++ way of doing things.
When you do see const attached to an object pointer in Objective-C, it is usually like this:
extern NSString * const SomeConstantString;
This declares SomeConstantString as a constant pointer to some non-constant object (in this case, an NSString). The pointer itself is constant, so your program can't change SomeConstantString to point to some other NSString object.

I know well that I can't change any character of the string because
the pointer is const.
No, the pointer is mutable. The characters it points to are const.
I can still mutate the object state using it's methods.
There is no const-correctness for Objective-C objects like there is in C++. The compiler does not care which messages (mutating or not) you send to a const object. So there's no sense in declaring a pointer to a const object. The cited framework method is an anomaly, probably an oversight.

Mind the difference:
// constant pointer
char * const str = "";
// pointer to constant (two equivalent ways)
const char * str = "";
char const * str = "";
The keyword const applies applies to whatever is immediately to its left. If there is nothing to its left, it applies to whatever is immediately to its right.
In Objective-C all method parameters are always passed by value. This includes primitives, structs, unions, and pointers, and any other made up type.
Note that you can't have variables of type object. A expression like NSObject o; produces a compiler error with message "Interface type cannot be statically allocated".
The only way to pass an object is passing a pointer. The pointer is passed as value, but lets the code inside the method reference the object and change it. So in a way, it is as if you are passing the object by reference (in reality you are passing the pointer by value).
When compiling an Objective-C program, the methods are turned into C functions, and each "message send" (aka "method call", though it isn't exactly the same) is ran using the runtime function objc_sendMsg. This function doesn't know or care if you qualified the object with const or not. If you want an immutable object, you have to code that immutability inside the object. Example:
// const qualifying an object is ignored whether in variables or method arguments:
const NSMutableArray *array = [NSMutableArray new]; // const is ignored
-(void)someMethod:(const NSMutableArray *)array { ... // const is ignored
// calling the methods that mutate the object works fine
[array removeAllObjects];

Related

Constants/Variable AND Non-Mutable/Mutable

Today one of my student asked me what is the technical difference between these two concepts
Constant and Variable
Non Mutable and Mutable
because we know Constants are Non Mutable and Variables are Mutable.
I told him that Mutable/Non Mutable is concept of Cocoa Framework and Constants/Variable is not. But i am not sure i was right
I know its usage but didn't find any proper technical answer.
You are right about constants being non-mutable and variables being mutable.
The mutable vs non-mutable in the cocoa framework are often ties to data structures (such as arrays, queues, dictionaries, etc).
Where mutable means we can alter the data structure (add/remove objects) and immutable means we can't modify it (just read).
Hope this helps
Constness in Objective-C referes to object references, but never to objects (as i. e. in C++). Mutability refers to objects.
// non-const reference to immutable string object
NSString *s = …;
// You can change the reference, …
s = …; // No error
// … but not the string object
[s appendString:…]; // Error
// const reference to immutable string object
const NSString* s = …;
// You can neither change the reference, …
s = …; // Error
// … nor the string object
[s appendString:…]; // Error
// non-const reference to mutable string object
NSMutableString *s = …;
// You can change the reference …
s = …; // No Error
// … and the string object
[s appendString:…]; // No error
// const reference to mutable string object
const NSMutableString *s = …;
// You cannot change the reference, …
s = …; // Error
// … but the string object
[s appendString:…];
So you can say that immutability is the "constness of (OOP) objects".
However constness of "variables" (to be more precise: C objects that are no Objective-C objects) is important to the compiler for optimization, because it is SSA. Immutability is important for many things in your design.
Even for (Objective-C) objects immutability is important and not as often considered as it should be. Especcially for "data classes" that are passed around, an immutable version should be considered making things easier. This applies to your own classes, too.

Explanation on const in Objective-C [duplicate]

What is the significance of the positioning of the
const
keyword when declaring a variable in Objective-C, for example:
extern const NSString * MY_CONSTANT;
versus
extern NSString * const MY_CONSTANT;
Using the first version in assignments produces warnings about "qualifiers from pointer target type" being discarded so I'm assuming that the second version ensures that the pointer address remains the same. I would really appreciate a more definitive answer though. Many thanks in advance!
In the first case, you are declaring a mutable pointer to an immutable const NSString object, whereas in the second case, you are declaring an immutable pointer to a mutable NSString object.
An easy way to remember this is to look at where the * is situated; everything to the left of it is the "pointee" type, and everything to the right of it describes the properties of the pointer.
extern const NSString * MY_CONSTANT;
- Pointer is variable , but the data pointed by pointer is constant.
extern NSString * const MY_CONSTANT;
- Pointer constant , but the data pointed by pointer is not constant.
In general, const always applies to the token just before the const. In the second case, the const means that the pointer is a constant, not the thing pointed at. The exception is when the const appears before anything that can meaningfully be constant, as in your first example. In this case it applies to the first type, in this case NSString, so its equivalent to extern NSString const * MY_CONSTANT

Wrap a struct inside a property into NSValue

I use NSValue to wrap a struct defined by me, but when the struct is accesed through a #property I get this error: Address of property expression requested.
Can this be done using the property or I shall store the struct in variable first?
Non-valid code:
NSValue *previousTileObj = [NSValuevalue:&self.previousTile withObjCType:#encode(RobotTile)];
Valid code:
RobotTile localPreviousTile = self.previousTile;
NSValue *previousTileObj = [NSValuevalue:&localPreviousTile withObjCType:#encode(RobotTile)];
You cannot take the address of the result of a call to the accessor of an object's property.
This is because the statement self.previousTitle is just syntactic sugar for the Objective-C message call [self previousTitle], which has semantics similar to that for function calls in that the resulting value has no real location in memory, and therefor it cannot have its address taken with the & operator.
You can, however, cheat the result into an addressable object by wrapping the accessor call within a C array literal. Since arrays are essentially pointers to their first element, this will result in a pointer to the desired data.
NSValue *previousTileObj = [NSValue value:(RobotTile []){self.previousTile}
withObjCType:#encode(RobotTile)];
You could take advantage of structure support in key-value coding and do:
NSValue *previousTileObj = [self valueForKey:#"previousTile"];

So very lost on initializing const objects

I have tried many times to understand the const keyword, but it just doesn't work out for me.
I want to declare an object that cannot be changed, which is to say, a constant object. For example, in the .h file:
extern MyClass *use_this_object;
and in the .m file:
MyClass *use_this_object;
+ (void) Initialize {
use_this_object = [MyClass new];
}
Now, where can I put a const so that other classes can access use_this_object but not modify it (assuming MyClass is immutable), while the MyClass class can initialize the variable?
Is this even possible? Or should I be using a static method to retrive the constant and not declare it extern at all?
There is no such thing as a "const object" in Objective-C. There are const pointers and there are immutable objects. A const pointer to an immutable object is what you're talking about, but you can't allocate those at run time.
For objects that can be allocated at compile time (and I only know of one, NSString), you can do this:
NSString * const kMyString = #"string";
This is a constant pointer to an (immutable) NSString. You read these things right-to-left.
To create what you want, you need a function or method with an internal static like this:
+ (Something *)something {
static Something *something = nil;
if (! something) {
something = [Something new];
}
return something;
}
This is preferable to using globals anyway for things other than true constants (like strings and integers).
It is up to you to make sure that Something is immutable.
EDIT Just a note about the above code. This is just an example of how to create a static object at runtime. There are many ways to do it with various trade-offs including using +initialize with a file static (which is currently my preferred way to create a singleton). Don't take the above code as the one-and-only-way. It's just the way that is closest to const because no other part of the program can get directly to the pointer.
I’d use the static method, seems much simpler.

Significance of const keyword positioning in variable declarations

What is the significance of the positioning of the
const
keyword when declaring a variable in Objective-C, for example:
extern const NSString * MY_CONSTANT;
versus
extern NSString * const MY_CONSTANT;
Using the first version in assignments produces warnings about "qualifiers from pointer target type" being discarded so I'm assuming that the second version ensures that the pointer address remains the same. I would really appreciate a more definitive answer though. Many thanks in advance!
In the first case, you are declaring a mutable pointer to an immutable const NSString object, whereas in the second case, you are declaring an immutable pointer to a mutable NSString object.
An easy way to remember this is to look at where the * is situated; everything to the left of it is the "pointee" type, and everything to the right of it describes the properties of the pointer.
extern const NSString * MY_CONSTANT;
- Pointer is variable , but the data pointed by pointer is constant.
extern NSString * const MY_CONSTANT;
- Pointer constant , but the data pointed by pointer is not constant.
In general, const always applies to the token just before the const. In the second case, the const means that the pointer is a constant, not the thing pointed at. The exception is when the const appears before anything that can meaningfully be constant, as in your first example. In this case it applies to the first type, in this case NSString, so its equivalent to extern NSString const * MY_CONSTANT