September 20, 2014
Also it's interesting waht is the correspondence between memory management, memory model and allocators? I know that std.allocator is in development. I guess that it should be considered in complex.
September 20, 2014
On Friday, 19 September 2014 at 15:32:38 UTC, Andrei Alexandrescu wrote:
> Please chime in with thoughts.
>

Coudln't we throw value types instead? (like in C++)
September 20, 2014
On Saturday, 20 September 2014 at 08:32:55 UTC, Dicebot wrote:
> On Saturday, 20 September 2014 at 08:20:47 UTC, Marc Schütz wrote:
>> I don't think ARC is needed.
>>
>> library RC + borrowing + uniqueness/moving = WIN
>
> You can't do polymorphic entity RC (like exceptions) without at least some help from compiler because language currently does not provide tools for lifetime control of classes. At least _some_ form of ARC is necessary.

I think we can, using templated alias this. We're not there yet, but it's probably feasable, seeing that Igor Stepanov already implemented multiple alias this [1]. With that and maybe a little opDispatch magic, it should be possible to making wrappers that are implicitly convertible to wrappers of parents of their inner types.

Granted, for exceptions there's more needed: There needs to be support for throwing and catching these wrappers, and for catching wrappers of derived types, too. But note that throw/catch itself doesn't involve copying, it's a moving operation, which might make it easier.

[1] https://github.com/D-Programming-Language/dmd/pull/3998
September 20, 2014
On Saturday, 20 September 2014 at 09:05:15 UTC, ponce wrote:
> On Friday, 19 September 2014 at 15:32:38 UTC, Andrei Alexandrescu wrote:
>> Please chime in with thoughts.
>>
>
> Coudln't we throw value types instead? (like in C++)

But how would you chain them? And they have to implement Throwable's interface.
September 20, 2014
On Saturday, 20 September 2014 at 09:05:24 UTC, Marc Schütz wrote:
> On Saturday, 20 September 2014 at 08:32:55 UTC, Dicebot wrote:
>> On Saturday, 20 September 2014 at 08:20:47 UTC, Marc Schütz wrote:
>>> I don't think ARC is needed.
>>>
>>> library RC + borrowing + uniqueness/moving = WIN
>>
>> You can't do polymorphic entity RC (like exceptions) without at least some help from compiler because language currently does not provide tools for lifetime control of classes. At least _some_ form of ARC is necessary.
>
> I think we can, using templated alias this. We're not there yet, but it's probably feasable, seeing that Igor Stepanov already implemented multiple alias this [1]. With that and maybe a little opDispatch magic, it should be possible to making wrappers that are implicitly convertible to wrappers of parents of their inner types.
>
> Granted, for exceptions there's more needed: There needs to be support for throwing and catching these wrappers, and for catching wrappers of derived types, too. But note that throw/catch itself doesn't involve copying, it's a moving operation, which might make it easier.
>
> [1] https://github.com/D-Programming-Language/dmd/pull/3998

Thinking further about it, we don't need templated `alias this`, because we can just have one `alias this` that returns `scope!this(T)` (this needs to be there anyway to be safe). It would automatically behave like a normal class with regard to polymorphy.

What's still needed then is a little magic to actually be able to throw and catch the wrapper.
September 20, 2014
On Saturday, 20 September 2014 at 09:05:24 UTC, Marc Schütz wrote:
> On Saturday, 20 September 2014 at 08:32:55 UTC, Dicebot wrote:
>> On Saturday, 20 September 2014 at 08:20:47 UTC, Marc Schütz wrote:
>>> I don't think ARC is needed.
>>>
>>> library RC + borrowing + uniqueness/moving = WIN
>>
>> You can't do polymorphic entity RC (like exceptions) without at least some help from compiler because language currently does not provide tools for lifetime control of classes. At least _some_ form of ARC is necessary.
>
> I think we can, using templated alias this. We're not there yet, but it's probably feasable, seeing that Igor Stepanov already implemented multiple alias this [1]. With that and maybe a little opDispatch magic, it should be possible to making wrappers that are implicitly convertible to wrappers of parents of their inner types.
>
> Granted, for exceptions there's more needed: There needs to be support for throwing and catching these wrappers, and for catching wrappers of derived types, too. But note that throw/catch itself doesn't involve copying, it's a moving operation, which might make it easier.
>
> [1] https://github.com/D-Programming-Language/dmd/pull/3998

Yeah but implicitly convertible to what? If you convert it to `Throwable` your reference counting facilities are circumvented resulting in dangling exception reference at point where `Throwable` gets caught.

Special casing catching such wrappers to still preserve original ref-counted type while pretending to be Throwable at call site sounds like a terrible hack, much worse than any sort of ARC complexity.
September 20, 2014
On Saturday, 20 September 2014 at 08:39:41 UTC, Walter Bright wrote:
>> E.g. TSX is coming even if there is
>> a bug in lower end CPUs. Suggest making performance oriented prototypes on
>> different architectures before concluding.
>
> I'd love to see it.

A 128 bit CAS instruction is at about 19-25 cycles, but a transaction on the other hand can by using xbegin/xend cover both refcounting, locking and rollback of multiple objects so you need cooperation from code gen. Basically all changes between xbegin/xend are kept in cache and written to memory upon success. On failure you have a slower fallback.

I don't know what that leads to in amortized cost reduction, but 30-70% might be possible if it is done right.

> As soon as you pass a reference to a function, that all goes out the window. There's a reason why Rust has invested so much effort in the notion of a "borrowed" pointer.

The pure @nogc crowd care less about safety, but you should be able to track this using dataflow?

>> 3. True, but you can keep the refcount at a negative offset for new-based
>> allocations. Besides it only affects those who do @nogc and they should know
>> what they are doing.
>
> If this is so simple, why doesn't everyone do it?

Never said performance and thread safe RC was easy. It is probably difficult to get below 10 cycles for inc/dec pairs even with excellent code gen...? And probably closer to 40 cycles for regular code gen. Just guessing.


September 20, 2014
On Saturday, 20 September 2014 at 09:19:21 UTC, Dicebot wrote:
> On Saturday, 20 September 2014 at 09:05:24 UTC, Marc Schütz wrote:
>> On Saturday, 20 September 2014 at 08:32:55 UTC, Dicebot wrote:
>>> On Saturday, 20 September 2014 at 08:20:47 UTC, Marc Schütz wrote:
>>>> I don't think ARC is needed.
>>>>
>>>> library RC + borrowing + uniqueness/moving = WIN
>>>
>>> You can't do polymorphic entity RC (like exceptions) without at least some help from compiler because language currently does not provide tools for lifetime control of classes. At least _some_ form of ARC is necessary.
>>
>> I think we can, using templated alias this. We're not there yet, but it's probably feasable, seeing that Igor Stepanov already implemented multiple alias this [1]. With that and maybe a little opDispatch magic, it should be possible to making wrappers that are implicitly convertible to wrappers of parents of their inner types.
>>
>> Granted, for exceptions there's more needed: There needs to be support for throwing and catching these wrappers, and for catching wrappers of derived types, too. But note that throw/catch itself doesn't involve copying, it's a moving operation, which might make it easier.
>>
>> [1] https://github.com/D-Programming-Language/dmd/pull/3998
>
> Yeah but implicitly convertible to what? If you convert it to `Throwable` your reference counting facilities are circumvented resulting in dangling exception reference at point where `Throwable` gets caught.

As I said, throw/catch is at its core a moving operation. For classes this isn't important (they are references), but for an RC wrapper it would be, so we could specify that.

Move-constructing from an lvalue in the context of D can be seen as a three-step process:

1) create a temporary, initialize with T.init
2) bit-swap the variable with the temporary
3) destroy the variable

It can be seen that the value that is to be moved (the RC wrapper) must be non-const (only at the head, it may still be tail-const).

Now, any generic RC type that wants to be implicitly convertible to its payload type must do this via borrowing in order to be safe (see my proposal at [1]). Using const-borrowing, we can guarantee that the wrapper will not be thrown (or moved, in general) as long as borrowed references to its payload exist:

    struct RC(T) {
        // ...
        T _payload;
        scope!(const this) borrow() {
            return _payload;
        }
        alias borrow this;
    }

This already solves avoiding dangling references to the exception: No references can be left behind when the exception is thrown, and the wrapper will not be destroyed, but moved, thus not releasing the exception's memory.

The second part is really "just" some way to transport the wrapper via the exception mechanism, including support for catching wrappers of derived exception types.

>
> Special casing catching such wrappers to still preserve original ref-counted type while pretending to be Throwable at call site sounds like a terrible hack, much worse than any sort of ARC complexity.

IMO it would only a hack _if_ they were indeed special cased. I'm sure we can find a more generic mechanism that would allow this to be implemented cleanly. Note that the other requirements I described above (borrowing, move semantics) are also things that just happen to be usable here: they are desirable in general, exceptions are just one possible application.

[1] http://wiki.dlang.org/User:Schuetzm/scope
September 20, 2014
On Saturday, 20 September 2014 at 04:48:33 UTC, Andrei
Alexandrescu wrote:
>> I basically agree with Walter on this one, no switch please, it's
>> maintenance nightmare for library devs.
>
> Why is it a maintenance nightmare?
>

Sorry, let's defer this, I might have overstated the negative
side-effects before carefully considering methods to mitigate the
impact.

>> My proposal would be to permanently use ARC for Throwable, no flags.
>
> How about other objects? Throwable is but the first step, and a good one to inform larger designs. We can't force RC on all objects on all applications.
>

I was viewing everything from a totally different perspective:
Normally what prevents an API to be nogc is exceptions, even
_emplace_ falls victim of this, in my line of reasoning I was
counting on the ripple effect to get us quite far, the remaining
issues could be fixed by refining the API to make it possible to
avoid allocations if desired.

However, since you had a different goal in mind, your solution
starts making more sense to me, it's also very easy to flip a
switch and benchmark individual applications, maybe people from
both camps will be surprised at the results.

>> What does the GC bring to exceptions that makes it sufficiently
>> invaluable to warrant two parallel implementations? It can't be about
>> performance, since _thrown_ exceptions are already in the slow path...
>> Backwards compatibility?
>
> Conversion from Throwable to Object.
>
>
> Andrei

The conversion could allocate on the GC, which would be
functionally backwards compatible and if the performance
degradation is a concern the code could be updated to avoid the
superfluous allocation by staying in the RCObject hierarchy.

Daniel
September 20, 2014
Andrei Alexandrescu:

>> Are you suggesting we implement ARC?
>
> Yes. -- Andrei

I think it's better first to design & implement a first version of memory ownership management, and then later add a reference counting scheme.

Bye,
bearophile