Cough. Actually, before ARC the ownership rules really kept RC traffic very low, and you could drive it lower still if you knew a bit about how ownership worked in your code ("these will balance and the object is already owned elsewhere...").
ARC just went mad with trying to give guarantees it really had no business making, and then hoping the compiler would be able to remove them again (difficult with message sending).
This caused some amusing bugs, for example a crash in the following method:
-someMethod:arg and:arg2
{
return 0;
}
How could this possibly crash? All it could possibly do is clear register AX and return.Well, with ARC enabled and in debug mode, it inserted code to first retain all the arguments, and then immediately release all the arguments. Apparently one of the args was a bogus pointer (framework-provided, so out of our control) and so it crashed.
return 0
is now considered "undefined behavior".Whatever.
You can try to defend yourself by stating the call is done by some framework but that just means the problem is still not in the language, it’s in the framework.
Second, whether the behavior is defined or undefined, the compiler has no business touching arguments that the code didn't tell it to touch. If it does so, it isn't fit for purpose and can be criticised as being unfit for purpose.
And the C standard is very clear and adamant that being in compliance with the standard is not, and in many ways cannot be, equivalent to being fit for purpose.
Last not least, I think we are probably not going to agree as to whether dereferencing unused arguments is a valid response to the presence of undefined behavior. See
https://blog.metaobject.com/2018/07/a-one-word-change-to-c-s...
Also, the Swift implementation is a bit questionable if performance is a goal. That is, why not try to remove the memory management from the inner loop? Probably the first thing to try is value types instead of reference types, which are more generally preferred anyway.
I believe all general purpose languages let the code allocate memory and therefore will let you allocate memory in a way inefficient to your task.
Hence why there is so much emphasis on value driven programming alongside protocols at WWDC talks.
ObjC had some elision tricks like objc_retainAutoreleasedReturnValue, but more importantly the optimizer was taught about RC manipulation. Swift then extended this with a new ABI that minimizes unnecessary mutations.
The big advantages of this scheme are efficient COW collections and a simpler FFI (very important with Swift). More generally RC integrates better. Imagine teaching the JS GC to walk the Java heap!