On 17 April 2014 22:28, Michel Fortin via Digitalmars-d <
digitalmars-d@puremagic.com> wrote:

> On 2014-04-17 03:13:48 +0000, Manu via Digitalmars-d <
> digitalmars-d@puremagic.com> said:
>
>  Obviously, a critical part of ARC is the compilers ability to reduce
>> redundant inc/dec sequences. At which point your 'every time' assertion is
>> false. C++ can't do ARC, so it's not comparable.
>> With proper elimination, transferring ownership results in no cost, only
>> duplication/destruction, and those are moments where I've deliberately
>> committed to creation/destruction of an instance of something, at which
>> point I'm happy to pay for an inc/dec; creation/destruction are rarely
>> high-frequency operations.
>>
>
> You're right that transferring ownership does not cost with ARC. What
> costs you is return values and temporary local variables.
>

Why would they cost? If a function receives a reference, it will equally
release it on return. I don't see why a ref should be bumped to pass it to
a function?
Return values I can see, because return values are effectively copying
assignments. But if the assignment is to a local, then the close of scope
implies a dec, which would again cancel out.


While it's nice to have a compiler that'll elide redundant retain/release
> pairs, function boundaries can often makes this difficult. Take this first
> example:
>
>         Object globalObject;
>
>         Object getObject()
>         {
>                 return globalObject; // implicit: retain(globalObject)
>         }
>
>         void main()
>         {
>                 auto object = getObject();
>                 writeln(object);
>                 // implicit: release(object)
>         }
>
> It might not be obvious, but here the getObject function *has to*
> increment the reference count by one before returning. There's no other
> convention that'll work because another implementation of getObject might
> return a temporary object. Then, at the end of main, globalObject's
> reference counter is decremented. Only if getObject gets inlined can the
> compiler detect the increment/decrement cycle is unnecessary.
>

Well in most cases of accessors like this, it would inline properly. It's a
fairly reliable rule that, if a function is not an inline candidate, it is
probably also highly unlikely to appear in a hot loop.

I don't follow why it needs to retain before returning though. It would
seem that it should retain upon assignment after returning (making it
similar to the situation below). Nothing can interfere with the refcount
before and after the function returns.


But wait! If writeln isn't pure (and surely it isn't), then it might change
> the value of globalObject (you never know what's in Object.toString,
> right?), which will in turn release object. So main *has to* increment the
> reference counter if it wants to make sure its local variable object is
> valid until the end of the writeln call. Can't elide here.
>
> Let's take this other example:
>
>         Object globalObject;
>         Object otherGlobalObject;
>
>         void main()
>         {
>                 auto object = globalObject; // implicit:
> retain(globalObject)
>                 foo(object);
>                 // implicit: release(object)
>         }
>
> Here you can elide the increment/decrement cycle *only if* foo is pure. If
> foo is not pure, then it might set another value to globalObject (you never
> know, right?), which will decrement the reference count and leave the
> "object" variable in main the sole owner of the object. Alternatively, if
> foo is not pure but instead gets inlined it might be provable that it does
> not touch globalObject, and elision might become a possibility.
>

Sure, there is potential that certain bits of code between the
retain/release can break the ability to eliminate the pair, but that's why
I think D has an advantage here over other languages, like Obj-C for
instance. D has so much more richness in the type system which can assist
here. I'm pretty confident that D would offer much better results than
existing implementations.

I think ARC needs to be practical without eliding of redundant calls. It's
> a good optimization, but a difficult one unless everything is inlined. Many
> such elisions that would appear to be safe at first glance aren't provably
> safe for the compiler because of function calls.


I'm very familiar with this class of problem. I have spent much of my
career dealing with precisely this class of problem.
__restrict addresses the exact same problem with raw pointers in C, and
programmers understand the issue, and know how to work around it when it
appears in hot loops.

D has some significant advantages that other ARC languages don't have
though. D's module system makes inlining much more reliable than C/C++ for
instance, pure is an important part of D, and people do use it liberally.

Reply via email to