October 17, 2018
On Wednesday, 17 October 2018 at 13:36:53 UTC, Stanislav Blinov wrote:

> Explicit cast from mutable to unsafe, on the other hand:

Blargh, to shared of course.
October 17, 2018
On 10/17/18 8:02 AM, Timon Gehr wrote:
> Now, if a class has only shared members, that is another story. In this case, all references should implicitly convert to shared. There's a DIP I meant to write about this. (For all qualifiers, not just shared).

When you say "shared members", you mean all the data is shared too or just the methods are shared?

If not the data, D has a problem with encapsulation. Not only all the methods on the class must be shared, but ALL code in the entire module must be marked as using a shared class instance. Otherwise, other functions could modify the private data without using the proper synch mechanisms.

We are better off requiring the cast, or enforcing that one must use a shared object to begin with.

I think any sometimes-shared object is in any case going to benefit from parallel implementations for when the thing is unshared.

-Steve
October 17, 2018
On Wednesday, 17 October 2018 at 13:25:28 UTC, Steven Schveighoffer wrote:
> On 10/16/18 8:26 PM, Manu wrote:
>> On Tue, Oct 16, 2018 at 2:20 PM Steven Schveighoffer via Digitalmars-d
>> <digitalmars-d@puremagic.com> wrote:
>>> There is in fact, no difference between:
>>>
>>> int *p;
>>> shared int *p2 = p;
>>> int *p3 = cast(int*)p2;
>> 
>> Totally illegal!! You casted away shared. That's as bad as casting away const.
>
> But if you can't do anything with shared data, how do you use it?
>
>> 
>>> and this:
>>>
>>> int *p;
>>> shared int *p2 = p;
>>> int *p3 = p;
>> 
>> There's nothing wrong with this... I don't understand the point?
>
> It's identical to the top one. You now have a new unshared reference to shared data. This is done WITHOUT any agreed-upon synchronization.

It isn't, you typo'd it (I originally missed it too).
> int *p3 = cast(int*)p2;

vs

> int *p3 = p;
October 17, 2018
On Wednesday, 17 October 2018 at 07:24:13 UTC, Stanislav Blinov wrote:
> On Wednesday, 17 October 2018 at 05:40:41 UTC, Walter Bright wrote:
>
>> When Andrei and I came up with the rules for:
>>
>>    mutable
>>    const
>>    shared
>>    const shared
>>    immutable
>>
>> and which can be implicitly converted to what, so far nobody has found a fault in those rules...
>
> Here's one: shared -> const shared shouldn't be allowed. Mutable aliasing in single-threaded code is bad enough as it is.

Could you explain that a bit more? I don't understand it, mutable -> const is half the reason const exists.

I was thinking that mutable -> shared const as apposed to mutable -> shared would get around the issues that Timon posted.
October 17, 2018
On 17.10.2018 15:40, Steven Schveighoffer wrote:
> On 10/17/18 8:02 AM, Timon Gehr wrote:
>> Now, if a class has only shared members, that is another story. In this case, all references should implicitly convert to shared. There's a DIP I meant to write about this. (For all qualifiers, not just shared).
> 
> When you say "shared members", you mean all the data is shared too or just the methods are shared?
> 
> If not the data, D has a problem with encapsulation. Not only all the methods on the class must be shared, but ALL code in the entire module must be marked as using a shared class instance. Otherwise, other functions could modify the private data without using the proper synch mechanisms.
> 
> We are better off requiring the cast, or enforcing that one must use a shared object to begin with.
> 
> I think any sometimes-shared object is in any case going to benefit from parallel implementations for when the thing is unshared.
> 
> -Steve

The specific proposal was that, for example, if a class is defined like this:

shared class C{
    // ...
}

then shared(C) and C are implicitly convertible to each other. The change is not fully backwards-compatible, because right now, this annotation just makes all members (data and methods) shared, but child classes may introduce unshared members.
October 17, 2018
On 17.10.2018 16:14, Nicholas Wilson wrote:
> 
> I was thinking that mutable -> shared const as apposed to mutable -> shared would get around the issues that Timon posted.

Unfortunately not. For example, the thread with the mutable reference is not obliged to actually make the changes that are performed on that reference visible to other threads.
October 17, 2018
On Wednesday, 17 October 2018 at 14:26:43 UTC, Timon Gehr wrote:
> On 17.10.2018 16:14, Nicholas Wilson wrote:
>> 
>> I was thinking that mutable -> shared const as apposed to mutable -> shared would get around the issues that Timon posted.
>
> Unfortunately not. For example, the thread with the mutable reference is not obliged to actually make the changes that are performed on that reference visible to other threads.

Yes, but that is covered by not being able to read non-atomically from a shared reference.
October 17, 2018
On Wednesday, 17 October 2018 at 07:20:20 UTC, Manu wrote:
> Shared is uninteresting and mostly useless as spec-ed, everyone knows this.
> Interaction with shared via barely-controlled blunt casting in
> @trusted blocks is feeble and boring. It doesn't really give us
> anything in practice that we don't have in C++. It's an uninspired
> design.

+1

I'm pretty sure it's great in theory, in practice it's another invasive type constructor, and not a particular well-understood or easy to deal with one.

The fact that this _type constructor_ finds its way into _identifiers_ create some concern: https://github.com/dlang/phobos/blob/656798f2b385437c239246b59e0433148190938c/std/experimental/allocator/package.d#L642
October 17, 2018
On 10/17/18 10:18 AM, Timon Gehr wrote:
> On 17.10.2018 15:40, Steven Schveighoffer wrote:
>> On 10/17/18 8:02 AM, Timon Gehr wrote:
>>> Now, if a class has only shared members, that is another story. In this case, all references should implicitly convert to shared. There's a DIP I meant to write about this. (For all qualifiers, not just shared).
>>
>> When you say "shared members", you mean all the data is shared too or just the methods are shared?
>>
>> If not the data, D has a problem with encapsulation. Not only all the methods on the class must be shared, but ALL code in the entire module must be marked as using a shared class instance. Otherwise, other functions could modify the private data without using the proper synch mechanisms.
>>
>> We are better off requiring the cast, or enforcing that one must use a shared object to begin with.
>>
>> I think any sometimes-shared object is in any case going to benefit from parallel implementations for when the thing is unshared.
>>
>> -Steve
> 
> The specific proposal was that, for example, if a class is defined like this:
> 
> shared class C{
>      // ...
> }
> 
> then shared(C) and C are implicitly convertible to each other. The change is not fully backwards-compatible, because right now, this annotation just makes all members (data and methods) shared, but child classes may introduce unshared members.

OK, so the proposal is that all data and function members are shared. That makes sense.

In one sense, because the class reference is conflated with the type modifier, having a C that isn't shared, actually have it's class data be shared, would be useful.

-Steve

October 17, 2018
On 10/17/18 9:58 AM, Nicholas Wilson wrote:
> On Wednesday, 17 October 2018 at 13:25:28 UTC, Steven Schveighoffer wrote:
>> It's identical to the top one. You now have a new unshared reference to shared data. This is done WITHOUT any agreed-upon synchronization.
> 
> It isn't, you typo'd it (I originally missed it too).
>> int *p3 = cast(int*)p2;
> 
> vs
> 
>> int *p3 = p;

It wasn't a typo.

It's identical in that both result in a thread-local pointer equivalent to p. Effectively, you can "cast" away shared without having to write a cast.

I was trying to demonstrate the ineffectiveness of preventing implicit casting from shared to mutable if you allow unshared data to implicitly cast to shared.

It's the same problem with mutable and immutable. It's why we can't allow the implicit casting. Explicit casting is OK as long as you don't later modify the data.

In the same vein, explicit casting of local to shared is OK as long as you don't ever treat the data as local again. Which should requires a cast to say "I know what I'm doing, compiler".

-Steve