Want reasonable reference counting? Disable automatic sharing of immutable

Stanislav Blinov stanislav.blinov at gmail.com
Sat Nov 13 23:08:01 UTC 2021


On Saturday, 13 November 2021 at 21:55:21 UTC, Steven 
Schveighoffer wrote:

> You are not getting that the GC collecting has nothing to do 
> with the pure function's executation. The GC hijacks the 
> current thread to do its business, and then passes back control 
> to the caller.

...while introducing side effects, which the caller of the pure 
function was promised WOULD NOT HAPPEN, by the interface of the 
pure function.

>> 
>>> Imagine it like a context switch to another thread that runs 
>>> the GC code, and then switches back to the pure code.
>> 
>> If I imagine that, the assert above should always hold. 
>> Because there should be no way that imaginary "another thread" 
>> would access main thread's `threadLocal`. Somehow, reality 
>> contradicts imagination.
>
> Actually, the GC can run finalizers from ANY thread. So 
> accessing thread locals in a GC finalizer is risky behavior 
> anyway.

The language allows this, and the runtime does this. There's no 
need for speculation. Risky or not. If a language guarantees 
something can't happen, it better not happen. Pure functions 
cannot mutate global state, except through arguments, in which 
case it's a weakly pure function. That's what the language 
guarantees. Pure functions can only call pure functions. That's 
what the language guarantees.

>>> It's similar to running some kernel code, or signal code -- 
>>> it's initiated by a separate entity, in this case the GC.
>>>
>>>> Unless that changed and GC isn't doing that anymore, that's 
>>>> a bug that's been open for some years now.
>>>
>>> It should be closed as invalid. Which bug is that?
>> 
>> https://issues.dlang.org/show_bug.cgi?id=19316
>
> Thanks! I closed it.

Cool. Then it's on you to reopen it back.

> The assert is incorrectly written,

Read `a`, call pure function, read `a`. Where is it possible for 
`a` to mutate, after first read and before second read? Can't be 
another thread, `a` is a thread-local int. Can't be the pure 
function, it's pure and cant mutate `a`. So where is it possible 
for `a` to mutate?

> as the thread local can change at any time if the GC happens to 
> run on the current thread, and happens to be finalizing a `Bad` 
> object (even if it was allocated via a different thread).

...Which means that anything that triggers collection (including 
allocation) cannot be pure. Which is exactly my point. Nor can it 
be @safe.

> This is how you set it up.

I have no words...

> Honestly, I think accessing thread locals in a GC destructor 
> should be in the spec as implementation-defined behavior.

So, then, should be any other side effects. Good luck with that.


More information about the Digitalmars-d mailing list