Why D is not popular enough?
Andrei Alexandrescu via Digitalmars-d
digitalmars-d at puremagic.com
Fri Aug 12 14:22:33 PDT 2016
On 08/12/2016 02:29 PM, H. S. Teoh via Digitalmars-d wrote:
> On Fri, Aug 12, 2016 at 02:21:04PM -0400, Andrei Alexandrescu via Digitalmars-d wrote:
>> On 08/12/2016 02:01 PM, H. S. Teoh via Digitalmars-d wrote:
>>> On Fri, Aug 12, 2016 at 02:04:53PM -0400, Andrei Alexandrescu via Digitalmars-d wrote:
>>>> On 08/12/2016 01:21 PM, Steven Schveighoffer wrote:
>>>>> On 8/12/16 1:04 PM, Jonathan M Davis via Digitalmars-d wrote:
>>>>>>
>>>>>> Honestly, I don't think that shared is broken.
>>>>>
>>>>> Yes. It is broken.
>>>>>
>>>>> shared int x;
>>>>> ++x; // error, must use atomicOp.
>>>>> x = x + 1; // OK(!)
>>>>
>>>> How is this broken and how should it behave? -- Andrei
>>>
>>> ?!
>>>
>>> Isn't it obvious that assigning to a shared int must require
>>> atomicOp or a cast? `x = x + 1;` clearly has a race condition
>>> otherwise.
>>
>> It is not to me, and it does not seem like a low-level race condition
>> to me (whereas ++x is).
>
> The problem is that the line between "low-level" and "high-level" is
> unclear and arbitrary.
I'd need to think a bit before agreeing or disagreeing, but it's a
plausible take. In this case fortunately, the matters can be distinguished.
> Doesn't ++x lower to x = x + 1 on some CPUs
> anyway (or vice versa, if the optimizer decides to translate it the
> other way)?
This doesn't matter. The question is what is explicit and what is
implicit in the computation.
++expr
is a RMW ("read-modify-write") expression, equivalent to:
((ref x) => { return x = cast(typeof(x)) (x + 1); })(expr)
In contrast,
expr1 = expr2 + 1
is an expression consisting of distinct read and write, both under the
control of the code written by the programmer. As I explained,
distinguishing in the general case when expr1 and expr2 refer to the
same memory location is not doable statically. So it stands to reason
that the compiler generates the code for one read and one write because
that is literally what it has been asked to do.
It may actually be the case that one wants to do x = x + 1 and exercise
a benign high-level race.
> Why should the user have to worry about such details?
What details are you referring to, and how would compiler technology
help with those?
> Wouldn't that make shared kinda useless to begin with?
It doesn't seem that way.
>> Currently the compiler must ensure that an atomic read and an atomic
>> write are generated for x. Other than that, it is the responsibility
>> of the user. The use of "shared" does not automatically relieve the
>> user from certain responsibilities.
>>
>> I agree that it would be nice to have stronger protection against
>> higher-level bugs, but those are outside the charter of "shared".
>> Consider:
>>
>> x = *p + 1;
>>
>> How would the compiler reject the right uses but not the case when p
>> == &x?
> [...]
>
> The compiler should reject it (without the appropriate casts) if p has a
> shared type, and the aliasing situation with x is unknown / unclear.
I think you are not right here.
Andrei
More information about the Digitalmars-d
mailing list