Nullability rules for C++ objects in Objective-C++ - objective-c++

(Please edit this post if I use incorrect C++ terms. I'm a total C++ noob.)
How does Objective-C nullability work with C++ objects in an Objective-C++ class?
For example, given the following type and function:
typedef struct
{
const Foo* fooArray;
uint32_t fooArrayLength;
} FooList;
uint32_t GetFoo(const std::string& bar, std::shared_ptr<const FooList>& result);
Is it legal to redefine GetFoo thusly?
uint32_t GetFoo(const std::string& _Nonnull bar, std::shared_ptr<const FooList _Nullable>& _Nonnull result);
Will I get any warnings from either clang or the static analyzer if I call GetFoo thusly?
GetFoo(nil, nil);

You've picked the two C++ cases where Nullability makes no sense. :-)
Your const FooList is a non-pointer type, so can never be nullptr (or NULL on older C++ compilers).
References are defined by the standard as never being nullptr either. Which makes sense, because nullptr is a pointer type, and the only way to go from a nullptr to a reference is dereferencing it, which ... well, nobody knows what happens when you dereference a null pointer.
However, the only case where you didn't specify nullability (the const Foo* in the struct) is actually where it would be valid.
At least if you're running on Apple's compilers. Technically, Apple's nullability is only part of the Objective-C (and by extension Objective-C++) standards, so is a nonstandard extension to C++ that depends on the compiler (hence the underscore at its start, which is reserved for compiler-specific keywords).
NB - For performance reasons, most C++ compilers just implement references as syntactic sugar on top of pointers, so in practice, you could do something evil like
Foo* myFoo = nullptr;
Foo& myFooRef = *myFoo;
and they wouldn't know you just made a nullptr reference, but that falls under "undefined" behaviour and as such is wrong code. However, I don't know if any Objective-C++ compiler currently analyzes nullability on C++ references. A quick test shows Apple's at least doesn't. Not sure if the static analyzer catches it either.
PS - If you tried to compile the above code, you should get an error about use of _Nullable (sic) on a non-pointer type.

Jordan Rose (of the Swift team at Apple) says:
References are not pointers, so they don't get nullability. But refs already may never be NULL according to the C++ standard.
So the question is moot.
However, regarding pointers:
[Regular pointers still get nullability in C++ and Objective-C++] (But there are a lot of rough edges around templates, unfortunately. ObjC++ nullability hasn't been a priority.)

Related

How to get UnsafeRawPointer on the swift object?

My app uses the native C++ lib, there is a method that takes as an argument void*
void foo(void * obj) { ... }
in swift I can call this method like this
func boo(obj: MyCustomObj) {
foo(&obj)
}
and looks like really I get a void pointer on the object, but if I try to get an UnsafeRawPointer on the object like this
func boo(obj: MyCustomObj) {
var pointer = &obj <---- Use of extraneous '&'
foo(pointer)
}
I got an error
Use of extraneous '&'
What is the problem here?
EDIT
I understood that using withUnsafe*** I can get the pointer to the data, but what to do if my method has 2 params, would it looks like this
withUnsafePointer(to: myObjFirst) {
pFirst in
withUnsafePointer(to: myObjSecond) {
pSecond in
foo(pFirst, pSecond)
}
}
The & syntax does not mean "the address of" or "pointer to" like in C. In Swift, it is an in-out expression.
These can be used to create implicit pointer conversions as a convenience, and that can seem like C's "pointer to" meaning, but it has very different rules and behaviors. For example, there is no promise that obj even has an address. It may be a tagged pointer. Passing it via an in-out expression may allocate memory and copy the value to make the call possible. Similarly, when passing a "pointer to an array," Swift will actually pass a pointer to a contiguous block of values (which may have been copied to make them contiguous) which is not the same as the actual Array struct.
It is not meaningful to say var pointer = &obj. There is no in-out reference there.
There is no general way to take long-lived pointers to objects in Swift without allocating your own memory (and this is rare). The memory model doesn't promise the kinds of lifetimes you'd need to make that sensible. If your code did compile the way you expect it to, the call to foo(pointer) would still be invalid because there's no promise that obj exists at that point and the pointer could be dangling. (There are no references to obj after the first line, so Swift can and often will destroy it, even though it's still "in scope.")
The foo(&obj) syntax is basically a shorthand for:
withUnsafePointer(to: obj) { foo($0) }
It exists to make it easier to call C functions, but it doesn't mean that Swift pointers are anything like C pointers.
For much more on Swift pointers, see Safely manage pointers in Swift from WWDC 2020.

ARC forbids Objective-C objects in structs or unions despite marking the file -fno-objc-arc

ARC forbids Objective-C objects in structs or unions despite marking the file -fno-objc-arc?
Why is this so?
I had the assumption that if you mark it -fno-objc-arc you don't have this restriction.
If you got this message try __unsafe_unretained. It is only safe, if the objects in the struct are unretained.
Example: If you use OpenFeint with ARC the Class OFBragDelegateStrings says this error in a struct.
typedef struct OFBragDelegateStrings
{
NSString* prepopulatedText;
NSString* originalMessage;
} OFBragDelegateStrings;
to
typedef struct OFBragDelegateStrings
{
__unsafe_unretained NSString* prepopulatedText;
__unsafe_unretained NSString* originalMessage;
} OFBragDelegateStrings;
Rather than using a struct, you can create an Objective-C class to manage the data instead.
That is because arc can't track objects in structs or unions (since they are at that point plain C pointers).
Even though you marked the file/class in question with -fno-objc-arc you might still pass an object controlled by arc to it as parameter, which would most likely result in a memory leak.
Looks like this now works without errors, probably after this change.
i.e., You can put normal (strong) pointers to Objective-C objects in a C struct. It is managed by ARC e.g., it is unretained when the struct is destructed. Verified with:
$ clang --version
Apple LLVM version 10.0.0 (clang-1000.11.45.2)

objective c 2.0 - keyword casting vs non-keyword casting

I come from a C# background and I am learning Objective-C. I was wondering if I could get some clarification on syntax. Thanks in advance for your help.
What is the difference between the lines of code shown below? Given that I know for sure that the type in the "tempItem" dictionary is an (NSString *) type and newsItem.pictureUrl is also an (NSString *):
Scenario 1:
newsItem.pictureUrl = [tempItem objectForKey:#"picture"];
Scenario 2:
newsItem.pictureUrl = (NSString *)[tempItem objectForKey:#"picture"];
I know what you mean. I also started out preferring to cast, since it clearly shows what you are doing. But after a while, it gets terribly tedious and you learn to omit it.
The fact that there are no generics, and that the containers only store objects, is a bit of a bummer, especially if you come from a language with generics. It means you are constantly and explicitly converting between objects and simple types (e.g. between NSNumber and int) and that there is no way, except to query [object class], to ensure you only get an NSString or an exception you can handle.
But the cast will not make any difference. If the object returned is not an NSString, and you cast it to one, it will make no difference. The cast does no implicit type checking, nor a conversion. It merely reinterprets the return value.
Casting between object types can basically only affect two things:
What warnings the compiler emits (e.g. "the class for this variable doesn't appear to have the method you're trying to call")
What properties the object has and how they work (e.g. the equivalent getter for self.awesome might be [self awesome] or [self isAwesome])
It emphatically does not affect what kind of object you get. The static types at compile time are just hints for the compiler. If you cast an object to a type that it isn't, you're just lying to the compiler.
In that particular case, it doesn't have any effect at all. Some people do write code like that, but AFAIK that's just because they find it comforting to just act like they're using a statically typed language (even though Objective-C isn't).
There's no difference between the two lines of code; it's purely stylistic.
The method objectForKey: here returns an object of type id, which is a generic object pointer. In Objective-C, an id can be implicitly converted to any Objective-C object type without a cast. The following two lines are equivalent:
id someId = ...;
NSString *someString = someId; // #1
NSString *someString = (NSString *)someId; // #2
This is similar to how in C, a pointer of type void* can be implicitly converted to a pointer to any other type without a cast (that is also true of Objective-C, but void* pointers are discouraged in Objective-C; that is not true in C++).
As far as type safety goes, both are equivalently unsafe. If the runtime type of the object is in fact the type you're casting it to (whether the cast is explicit or implicit) or a subclass thereof, then everything will work as intended. If the runtime type is not what you're expecting, then most likely an NSException will be thrown with the common object does not response to selector error, due to calling a function that doesn't exist for that type. It's also possible you might crash with a segmentation fault due to accessing an ivar that doesn't exist or has an unexpected value (since the object really isn't that type).
If you're unsure of that object's runtime type, you should check its runtime type with the -class or -isKindOfClass: methods, and then only take action if it's a particular type. Prefer using-isKindOfClass:`, since that still works with subclasses, as opposed to comparing the class for exact equality with a particular class. For example:
id someId = ...;
if ([someId isKindOfClass:[NSString class])
{
// It's an NSString
NSString *someString = someId;
// Do stuff with someString...
}
The type of an Objective-C instance is really only useful for determining the appropriate amount of memory to allocate for creation of the instance, and for static analysis (code completion, compilation etc). At run time the instances are all represented by id's and the actual type of the object means much less. This dynamic behavior is by design, and allows a great amount of flexibility when designing ObjC applications.
You will see very little typecasting in the typical ObjC program.
Casting is only really necessary when you want to have the compiler understand the type for a call, so that it doesn't give "may not respond" warnings.

does objective-c methods support "pass by value"?

Does objective-c methods support "pass by value"? Or perhaps to be more specific:
Is the default behavior for parameters passed into a method pass-by-reference?
If yes, are there any variations from this in some circumstances - for example if the parameter is just a basic int as opposed to an object? (or is this not relevant in objective-c)
Is there anyway to have a method support pass-by-value for a basic variable such as int?
Is there anyway to have a method support pass-by-value for an object? (I'm assuming no here, but for completeness will ask. Of course one could within the message do the copy yourself, however for this approach I'll consider this not to be something objective-c methods offers you, i.e. rather it was a do-it-yourself)
thanks
Objective-C does not support references, at least not in the C++ sense of the term.
All Objective-C objects are allocated on the heap, and therefore all "object variables" must in fact be pointer types. Whether a pointer can be considered to be effectively the equivalent of a reference is open to debate. When talking C++ for example, there are clear semantic differences (otherwise, what's the point...)
So to answer your questions:
No, Objective-C only supports pass-by-value. If you pass an object pointer to a method, you pass the pointer by value - you are not passing a reference.
There is no inherent difference between objects and primitives in this regard, apart from the fact that objects are always referred to by pointer, never by value. You can pass a primitive type pointer in if you like.
Yes. This is always the case. Again, if you pass in a pointer to a primitive, you are passing a pointer by value, not a reference.
You're pretty much bang on the mark with this one, other than the fact that you're passing around pointers, not references.
No. It's pass-by-value by default, like in C. Except for the fact that for the Objective C class instance references, the value is a reference. So Objective C class instances are passed effectively by reference.
N/A
See 1.
Not really. You can serialize, pass the string, and recreate inside. Or you can have the object store its ivars as a structure and pass that structure by value. Some objects support cloning.

Is it wrong to use the dot syntax as a getter?

I know that the . is a shortcut for a setter. Sometimes, I use that kind of code:
cell.textLabel.text = [NSString stringWithFormat:#"this is row %i", indexPath.row];
This works as expected, but I was wondering, is it better (or more correct maybe?) to write
cell.textLabel.text = [NSString stringWithFormat:#"this is row %i", [indexPath row]];
Or, in other words, should I use the dot syntax only with the = operator, like
aTextField.text = #"whatever";
Any links/docs are welcome, thanks :)
PS. In case you didn't see the tag, I'm talking about iOS here.
Dot (.) is not only a shortcut for setter, it's shortcut for getter too. You can use dot for getter too. There is no problem, neither this is bad practice. From Obj-C 2.0 programming guide, "You can use the dot syntax to invoke accessor methods using the same pattern as accessing structure elements. The dot syntax is purely “syntactic sugar”". Note that, it is saying about accessor method, not only setter.
It's a matter of taste.
I prefer not to use the dot syntax for various reasons:
When using dot syntax, it's much harder to find only the places in your code where you set an value. Search for setValue: is much easier than searching for .value
As a long time C programmer, my brain is wired to associate the dot syntax with accessing struct members. I find it rather hard to get used to the dot syntax in a different scope.
The setXY: syntax close follows the natural language much closer. Makes reading someone else's code so much easier.
"." is a shortcut for accessing a #property (which may, by the way, be readonly). From the syntax point of view whether this is a getter or a setter depends on the operand position:
self.enabled = NO; // setter
BOOL isEnabled = self.enabled; // getter
self.selected = self.enabled = NO; // this is OK too
It's coding style so neither is better.
I would note two things though.
As a long time Objective C code I prefer the [indexPath row] as it is consistent with the rest of the code and for a set I would use [aTextField setText:#"whatever"]
But if you need to use the . notation for keypaths the accessing the same variable via method notation in the same piece of code will seem odd.
Apple documentation says
Objective-C provides a dot (.) operator that offers a compact and convenient syntax you can use as an alternative to square bracket notation ([]s) to invoke accessor methods.
and
myInstance.value = 10;
printf("myInstance value: %d", myInstance.value);
The dot syntax is purely “syntactic
sugar”—it is transformed by the
compiler into invocation of accessor
methods (so you are not actually
accessing an instance variable
directly). The code example above is
exactly equivalent to the following:
[myInstance setValue:10]; printf("myInstance value: %d", [myInstance value]);
Using the dot syntax is not coding style or a matter of taste!
The dot syntax is for accessing properties. The message sending syntax is for dispatching methods. They are conceptually two different things. Legacy and backwards compatibility to Objective-C 1.0 unfortunately makes them interchangeable, which has caused allot of confusion.
Weather to user the dot-syntax or not is dead simple:
If a public header declares something as property, then access it as a property using the dot-syntax, as the author of the interface explicitly intended!
If a public header declares something as a method, then access it using the message sending syntax, as the author of the interface explicitly intended!
Make NO exceptions.
The hard question is, should you declare something as a property, and thus tell your clients that doit-syntax should be used, or should you declare a method? The simple answer is:
Use properties for states (is something).
Use methods for behaviors (do/calculate something).
Another rule of thumb is that properties should be self-contained, there should be no other way to change the value of the property but to set the property itself. This is Not a hard rule, use common sense, many sensible exceptions exist. For example a hidden property that can be changed with setHidden:animated: method.