April 15, 2013
Am 14.04.2013 19:07, schrieb Robert:
>> Does it mean you disagree with proposed compiler changes and with the idea we have to create weak reference functionality instead of recreating it every time it is needed (beside of theoretical danger such approach already showed it as a bad thing with `std.stdio.File` as I wrote)?
>>
> 
> 
> A weak reference could actually be implemented in the library relatively easy. ( I basically did it for std.signals2 )

My memories tell me that I was never able to make a _thread safe_ weak reference, though. I don't remember exactly, but I think that it was because the dispose event happens after all threads have already restarted. This means that some thread could extract a strong reference from the weak reference before the weak reference knows that the underlying object has been destroyed, thus creating a dangling pointer.

April 15, 2013
> My memories tell me that I was never able to make a _thread safe_ weak reference, though. I don't remember exactly, but I think that it was because the dispose event happens after all threads have already restarted. This means that some thread could extract a strong reference from the weak reference before the weak reference knows that the underlying object has been destroyed, thus creating a dangling pointer.
> 
You are right, it is not thread safe. Some hook would be needed that gets called before threads are resumed. It is not an issue for std.signals2 because it is not meant to be thread safe.

Best regards,
Robert

April 15, 2013
> Yes, this is how array of weak references will work because this is how weak references work. And this shows one mustn't implement general facilities in every case they are needed as he will do mistakes and will complicate thinks for himself.
> 

If an array of weak references works this way, then it is also easily implementable in the library. For thread safe weak references another hook would be necessary though, as Soenke has pointed out.

My current approach is to use a /simplified/*) lock-free list. Simplified because I make use of the way the GC works, so it is not thread safe in general. The lazy approach would make this unnecessary.

Maybe I go for lazy, the more sophisticated solution can be implemented later on if really deemed necessary.


*) It is still brain-fuck though.

April 15, 2013
> 2. Make regular D objects on closures [4] to be able to know when delegate's outer scope is destroyed (this will auto-fix both [5] and [2], see Comment 2 of [2] for code example)

I still don't understand what that buys us. Having a closure being an object would make it possible to use a weak reference, but why would you want that? The signal would be the only one to hold a reference to the lamdas context, if this reference was a weak one, then the memory would be claimed immediately. This is why std.signals2 holds a strong ref to the delegate context of a wrapping closure and a weak ref to the target object.



April 15, 2013
15.04.2013 13:07, Robert пишет:
>> 2. Make regular D objects on closures [4] to be able to know when
>> delegate's outer scope is destroyed (this will auto-fix both [5] and
>> [2], see Comment 2 of [2] for code example)
>
> I still don't understand what that buys us. Having a closure being an
> object would make it possible to use a weak reference, but why would you
> want that? The signal would be the only one to hold a reference to the
> lamdas context, if this reference was a weak one, then the memory would
> be claimed immediately. This is why std.signals2 holds a strong ref to
> the delegate context of a wrapping closure and a weak ref to the target
> object.

With your `std.signals2` one can't e.g. forward delegate connection like this:
---
/// Usage: don't pass struct pointer delegates as `del`.
void f(void delegate() del)
{
    obj.event.connect(del);
}
---
as you require explicit passing an object owning a delegate.

But it is completely unnecessary as delegate do know where it was born from and the fact this information isn't tracked when a closure is created is a language design issue. One of those fixing which is easy, will not break any code and will improve things a lot.

-- 
Денис В. Шеломовский
Denis V. Shelomovskij
April 15, 2013
On Monday, 15 April 2013 at 12:07:19 UTC, Denis Shelomovskij wrote:
> 15.04.2013 13:07, Robert пишет:
>>> 2. Make regular D objects on closures [4] to be able to know when
>>> delegate's outer scope is destroyed (this will auto-fix both [5] and
>>> [2], see Comment 2 of [2] for code example)
>>
>> I still don't understand what that buys us. Having a closure being an
>> object would make it possible to use a weak reference, but why would you
>> want that? The signal would be the only one to hold a reference to the
>> lamdas context, if this reference was a weak one, then the memory would
>> be claimed immediately. This is why std.signals2 holds a strong ref to
>> the delegate context of a wrapping closure and a weak ref to the target
>> object.
>
> With your `std.signals2` one can't e.g. forward delegate connection like this:
> ---
> /// Usage: don't pass struct pointer delegates as `del`.
> void f(void delegate() del)
> {
>     obj.event.connect(del);
> }
> ---
> as you require explicit passing an object owning a delegate.
>
> But it is completely unnecessary as delegate do know where it was born from and the fact this information isn't tracked when a closure is created is a language design issue. One of those fixing which is easy, will not break any code and will improve things a lot.

Even with that explanation, I still don't see the problem.
April 16, 2013
15.04.2013 20:15, deadalnix пишет:
> On Monday, 15 April 2013 at 12:07:19 UTC, Denis Shelomovskij wrote:
>> 15.04.2013 13:07, Robert пишет:
>>>> 2. Make regular D objects on closures [4] to be able to know when
>>>> delegate's outer scope is destroyed (this will auto-fix both [5] and
>>>> [2], see Comment 2 of [2] for code example)
>>>
>>> I still don't understand what that buys us. Having a closure being an
>>> object would make it possible to use a weak reference, but why would you
>>> want that? The signal would be the only one to hold a reference to the
>>> lamdas context, if this reference was a weak one, then the memory would
>>> be claimed immediately. This is why std.signals2 holds a strong ref to
>>> the delegate context of a wrapping closure and a weak ref to the target
>>> object.
>>
>> With your `std.signals2` one can't e.g. forward delegate connection
>> like this:
>> ---
>> /// Usage: don't pass struct pointer delegates as `del`.
>> void f(void delegate() del)
>> {
>>     obj.event.connect(del);
>> }
>> ---
>> as you require explicit passing an object owning a delegate.
>>
>> But it is completely unnecessary as delegate do know where it was born
>> from and the fact this information isn't tracked when a closure is
>> created is a language design issue. One of those fixing which is easy,
>> will not break any code and will improve things a lot.
>
> Even with that explanation, I still don't see the problem.

Do you mean that tracking an object with a delegate whenever it goes to just know where it's outer scope is destroyed is not a problem?

-- 
Денис В. Шеломовский
Denis V. Shelomovskij
April 16, 2013
On Tuesday, 16 April 2013 at 05:39:32 UTC, Denis Shelomovskij wrote:
> Do you mean that tracking an object with a delegate whenever it goes to just know where it's outer scope is destroyed is not a problem?

Delegate context is allocated on the heap, unless compiler can prove it can do it on stack. context is destroyed when no live pointer point to it.

You still didn't explain why an object is better than the actual delegate mecanism.
April 16, 2013
16.04.2013 10:10, deadalnix пишет:
> On Tuesday, 16 April 2013 at 05:39:32 UTC, Denis Shelomovskij wrote:
>> Do you mean that tracking an object with a delegate whenever it goes
>> to just know where it's outer scope is destroyed is not a problem?
>
> Delegate context is allocated on the heap, unless compiler can prove it
> can do it on stack. context is destroyed when no live pointer point to it.
>
> You still didn't explain why an object is better than the actual
> delegate mecanism.

Sorry, I really don't understand what you don't understand.

Let's consider example from Issue 9603 Comment 2 [1]. Do you think such code must not work?

Also you can look through Issue 9601 discussion.

[1] http://d.puremagic.com/issues/show_bug.cgi?id=9603#c2
[2] http://d.puremagic.com/issues/show_bug.cgi?id=9601

-- 
Денис В. Шеломовский
Denis V. Shelomovskij
April 16, 2013
On Tuesday, 16 April 2013 at 07:55:51 UTC, Denis Shelomovskij wrote:
> Sorry, I really don't understand what you don't understand.
>
> Let's consider example from Issue 9603 Comment 2 [1]. Do you think such code must not work?
>
> Also you can look through Issue 9601 discussion.
>
> [1] http://d.puremagic.com/issues/show_bug.cgi?id=9603#c2
> [2] http://d.puremagic.com/issues/show_bug.cgi?id=9601

The code in 9603 is completely broken. It should compile and run, but what it does is undefined as o is finalized when delegates have reference to it.

I don't see how changing delegate into object would change anything, as the code would be broken in the same way for the same reason.