Personally I'm partial to deterministic schemes akin to IBM Metronome, where GC runs in bounded static time.
Could you give any examples of common use cases and ways that people perform these “optimisations”?
Another big one is trying to allocate as much as possible on the stack, either through the language like c/c++/c# or by using local variables and hoping the compiler will do the right thing for you with java. A lot of the work gone into java vm's over the decades have been trying to improve this. Even java sacrifices it's OO purity to make integers and floats value types on the stack, that was to get non-laughable performance.
> This...isn’t true.
It's not even remotely controversial, saying garbage collection is slower is like saying water is wet.
Most popular dynamic languages don’t use garbage collection under the hood anyway. In Python and many other runtimes, it’s primarily reference counted.
Just a little bit overconfident.
Scattering atomic ref counts everywhere gets extremely expensive very quickly.
It hasn’t been a problem for me in over a decade in a multitude of languages. On Java codebases? I’ve witnessed some frightening levels of sloppiness that are only solvable with a profiler.
GC was a mistake. The main reason it is still used outside scripting languages is the notion that non-GC languages need to be low level. Which in practice is kind of true just because we haven't had any real competition in that area.
Now we also have rust, but rust is new and also has a low-level aura, making comparisons to high-level languages difficult.
That Go has a GC is a shame, such a missed opportunity.
Typical programmer is taught nothing about memory management, till maybe they learn bits and pieces (often by hearsay and cargo culting). It doesn't matter if we're talking manual or automatic. Without such understanding one cannot write performant code or make a good architecture.
Also - a good working definition of low-level language is language that makes you care about things irrelevant to your task...
But it helps. And is something you need to reason about regardless. Being explicit about it isn't a huge overhead but has lots of benefits.
And when you need multithreaded/concurrency it goes to atomic operations, cache coherency traffic, memory and compiler barriers.
It's cool that you don't need to bother with specifying the type as being std::shared_ptr<T> or Arc<T>, but it's not particularly novel, either. It's "just" syntax sugar (or lack of syntax sugar I guess?)
[1] https://clang.llvm.org/docs/AutomaticReferenceCounting.html#...
ARC can't do anything magic here vs. something like really careful use of std::move & const references.
Are you just referring to standard RVO? If you return a std::shared_ptr in C++ today you won't get the equivalent of retain+release, either, RVO avoids that.
> For example, if the user puts logging statements in retain, they should not be surprised if those statements are executed more or less often depending on optimization settings
> In general, ARC does not perform retain or release operations when simply using a retainable object pointer as an operand within an expression
> However, C and C++ already call this undefined behavior because the evaluations are unsequenced, and ARC simply exploits that here to avoid needing to retain arguments across a large number of calls.
> ARC performs no extra mandatory work on the caller side, although it may elect to do something to shorten the lifetime of the returned value.
That's optional tho, and I never use it that way.
Are you using your own implementation of retain & release or something?
@property (strong, nonatomic) UIView* unselectedTabsView;
"nonatomic" means avoid synchronization code. This code is not thread safe for that reason, but I never do cross-thread access anyways.