shared - i need it to be useful

Steven Schveighoffer schveiguy at gmail.com
Thu Oct 18 22:35:13 UTC 2018


On 10/18/18 5:22 PM, Manu wrote:
> On Thu, Oct 18, 2018 at 12:15 PM Steven Schveighoffer via
> Digitalmars-d <digitalmars-d at puremagic.com> wrote:
>>
>> On 10/18/18 2:55 PM, Manu wrote:
>>> On Thu, Oct 18, 2018 at 7:20 AM Steven Schveighoffer via Digitalmars-d
>>> <digitalmars-d at puremagic.com> wrote:
>>>>
>>>> On 10/18/18 10:11 AM, Simen Kjærås wrote:
>>>>> On Thursday, 18 October 2018 at 13:35:22 UTC, Steven Schveighoffer wrote:
>>>>>> struct ThreadSafe
>>>>>> {
>>>>>>      private int x;
>>>>>>      void increment()
>>>>>>      {
>>>>>>         ++x; // I know this is not shared, so no reason to use atomics
>>>>>>      }
>>>>>>      void increment() shared
>>>>>>      {
>>>>>>         atomicIncrement(&x); // use atomics, to avoid races
>>>>>>      }
>>>>>> }
>>>>>
>>>>> But this isn't thread-safe, for the exact reasons described elsewhere in
>>>>> this thread (and in fact, incorrectly leveled at Manu's proposal).
>>>>> Someone could write this code:
>>>>>
>>>>> void foo() {
>>>>>        ThreadSafe* a = new ThreadSafe();
>>>>>        shareAllOver(a);
>>>>
>>>> Error: cannot call function shareAllOver(shared(ThreadSafe) *) with type
>>>> ThreadSafe *
>>>
>>> And here you expect a user to perform an unsafe-cast (which they may
>>> not understand), and we have no language semantics to enforce the
>>> transfer of ownership. How do you assure that the user yields the
>>> thread-local instance?
>>
>> No, I expect them to do:
>>
>> auto a = new shared(ThreadSafe)();
> 
> I don't have any use for this design in my application.
> I can't use the model you prescribe, at all.

Huh? This is the same thing you are asking for. How were you intending 
to make a thread-safe thing sharable? Surely it will be typed as shared, 
right? How else will you pass it to multiple threads?

> 
>>> I think requiring the cast is un-principled in every way that D values.
>>
>> No cast is required. If you have shared data, it's shared. If you have
>> thread local data, it's unshared. Allocate the data the way you expect
>> to use it.
> 
> All data is thread-local, and occasionally becomes shared during periods.
> I can't make use of the model you describe.

If data is shared, it is shared. Once it is shared, it never goes back.

In your model, everything is *assumed* shared, so that's what you need 
to do, initialize it as shared. It still works just as you like. Even if 
you never actually share it, or share it periodically.

> My proposal is more permissive, and allows a wider range of
> application designs. What are the disadvantages?

The opposite is true. More designs are allowed by restricting casting as 
I have demonstrated many times.

>> It's only if you intend to turn unshared data into shared data where you
>> need an unsafe cast.
> 
> It's unnecessary though, because threadsafe functions are threadsafe!
> You're pointlessly forcing un-safety. Why would I prefer a design that
> forces unsafe interactions to perform safe operations?

No unsafe interactions are required for a type that defensively is 
shared. Just make it always shared, and you don't have any problems.

>> It's not even as difficult as immutable, because you can still modify
>> shared data. For instance, the shared constructor doesn't have to have
>> special rules about initialization, it can just assume shared from the
>> beginning.
> 
> Your design us immutable, mine is const.

No, your design is not const, const works on normal types. It's 
applicable to anything.

Your design is only applicable to special types that experts write. It's 
not applicable to int, for instance. It feels more like a special 
library than a compiler feature.

> Tell me, how many occurrences of 'immutable' can you find in your
> software? ... how about const?

I generally use inout whenever possible, or const when that is more 
appropriate. But that is for methods.

For data, I generally use immutable when I want a constant.

But like I said, something can't be both shared and unshared. So having 
shared pointers point at unshared data makes no sense -- once it's 
shared, it's shared. So shared really can't be akin to const.

> Which is more universally useful? If you had to choose one or the
> other, which one could you live without?

I would hate to have a const where you couldn't read the data, I 
probably would rather have immutable.

I said I would stop commenting on this thread, and I didn't keep that 
promise. I really am going to stop now. I'm pretty sure Walter will not 
agree with this mechanism, so until you convince him, I don't really 
need to be spending time on this.

We seem to be completely understanding each others mechanisms, but not 
agreeing which one is correct, based on (from both sides) hypothetical 
types and usages.

-Steve


More information about the Digitalmars-d mailing list