Hacker News new | ask | show | jobs
by seanalltogether 107 days ago
At this point in my career, I can't go back to a language that doesn't have support for Optionals or compiler validation of nullable types. I can sacrifice async or fancy stream apis, but I will never go back to chasing null pointer exceptions on a daily basis.
5 comments

Obj-C does have a "nonnull" annotation now (apparently added to assist Swift interop). One of the final jigsaw pieces turning it into a really pleasant language.
It is a really pleasant language, but I think the <nonnull> annotation is for initialization only - compiler checking against initializing an object ptr with a null value - and does not prevent crashing when addressing an already released object
> does not prevent crashing when addressing an already released object

I don’t know what behavior you’d expect here or in what situation you’d encounter this for a nonnull reference. You’d have to be really living dangerously I’d imagine. The footgun was that nonnull isn’t enforced. And anyway, leaks were more the issue.

That was exactly my point.

GP mentioned ‘chasing null pointer exceptions’, then parent mentioned that the language ’now does have nonnull annotation’, prompting me to explain that that does not prevent null pointer exceptions.

So, not living a dangerously. All that can be held against me is being “dangerously” imprecise on HN - definitely not good either

nonnull doesn't really do anything in pure objc. It warns if you assign the nil literal to a nonnull pointer and that's it. The annotation is almost entirely for the sake of Swift interop (where it determines if the pointer is bridged as an Optional or not).
I don't think objc has the equivalent of a null pointer exception. You can freely send messages to a deallocated object. Since ARC, it is rare, at least in my experience, running into any memory related issues with objc.
You can send messages to `nil`, but the inverse isn't universally true. APIs like

  [text stringByAppendingString:other]; 
will throw an `NSInvalidArgumentException` if `other` is nil.
That is an API choice from Apple that isn't something inherent to objc. This is true of any method. It is up to the person who wrote it to decide how to handle a nil being passed in.
Frankly, all of this is an API and ABI choice from Apple. It was not the case that sending a message to nil always returned nil/NULL/0 before Apple's Intel transition, and the subsequent introduction of their modern Objective-C ABI. From Apple's 2006 Cocoa coding guidelines:

> If the message sent to nil returns anything other than the aforementioned value types (for example, if it returns any struct type, any floating-point type, or any vector type) the return value is undefined

And from the Intel transition guide:

> messages to a nil object always return 0.0 for methods whose return type is float, double, long double, or long long. Methods whose return value is a struct, as defined by the Mac OS X ABI Function Call Guide to be returned in registers, will return 0.0 for every field in the data structure. Other struct data types will not be filled with zeros. This is also true under Rosetta. On PowerPC Macintosh computers, the behavior is undefined.

This wasn't just a theoretical issue, either. You could run the same Objective-C code on a PPC Mac, an Intel Mac, the iPhone Simulator, and an iPhone – you'd get a zero-filled struct on Intel and the Simulator, while you'd get garbage on PPC and on real iPhone hardware.

You can send messages to null, sendings messages to a deallocated pointer is going to be a bad time.
It’s nice not to crash, but unexpected null can still cause bugs in ObjC when the developer isn’t paying attention.

Having done both ObjC with nonnull annotations, and Swift, I agree that it’d be hard to forgo the having first-class support for Optionals

When Swift 1 came out, I was migrating an ObjC app that used CoreData to it and found a bug where nullable cols in the CoreData schema got non-nullable properties in the autogenerated Swift. Found out when I had a non-nullable property actually get set to null at runtime, and the compiler wouldn't let me add a check that it's null.
Objective-C did not have null pointer exceptions, though some libraries added them.
If you use Objective-C objects, operations on null pointers are just a no-op, so there is not such thing as chasing exceptions.
So you silently ignore something being null when you don't expect it to be? That sounds even worse.
It's just that

    pointer?.doSomething()
is the default. Le horreur!
The Swift way is safer, but I don't like it much either. The ? explicitly says you want to ignore null, so that's fine. The problem is there's no convenient way to throw exception if null, so you're encouraged to overuse ?, as I think you alluded to. (! will crash the entire program instead.) Swift error handling is overall pretty complex too.

Ironically the JS or Py error handling is actually the safest for high-level code. Exceptions are easy to work with and hard to ignore by accident. Very few ways to crash entirely. And Rust's errors are good for systems code.

Not really, because doSomething is not called if reference/pointer is null, whereas in Objective-C there is still a message that is sent to the NULL recipient.
No, the messenger identifies the NULL recipient and does not send the message.