On 8/12/16 7:22 PM, Andrei Alexandrescu wrote:
On 8/12/16 6:58 PM, Steven Schveighoffer wrote:
On 8/12/16 2:04 PM, Andrei Alexandrescu 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


It's broken because it's inconsistent. If the compiler is going to
complain about races in one case, but not in other equivalent cases,
then the feature is useless.

But ++expr and expr1 = expr1 + expr2 are fundamentally different.

It's not expr2, it's 1.

And no they aren't fundamentally different. Don't think like a compiler.

If all I have to do to avoid compiler complaints is rewrite my
expression in an equivalent way, then what is the point of the
complaint? At that point, it's just a style guide.

A bunch of rewrites to seemingly identical behavior to avoid type errors
are de rigoeur in so many situations. This is no different.

It's not a type error. We have const, and pure, and @safe, which require you to write code in a way that enforces a guarantee.

shared does this in a half-assed way. It's not effective. It's like C++ const is not effective at guaranteeing anything stays constant.

What should it do? If I knew that, then I'd have proposed a DIP by now.
It's not an easy problem to solve. I don't think you can "solve" races
because the compiler can't see all interactions with data.

++expr contains a low-level race that is worth removing. Extending that
to a variety of sub-patterns of expr1 = expr2 + expr3 seems a terrible
idea to me.

I agree that in general races cannot be detected and prevented. ++expr1 is an obvious race, and it is detected and prevented. But it gives the impression that the compiler isn't going to let you make races. It gives the impression that the language has some level of guarantee about avoiding multi-threaded mistakes. It doesn't. It doesn't guarantee anything. It's just a helpful trick in one specific case.

I don't know what the right way to handle shared is. My opinion is simply that shared needs special handling from the user. The compiler isn't going to help you make thread-safe code, but at least allows you to mark where the unsafe code could be (by using shared type modifier).

At first glance, it seems that shared data shouldn't be usable without
some kind of explicit usage syntax. x = x + 1 is too innocuous looking.
It's not going to "solve" the issue, but it makes the code easier to
pick out.

We discussed this at a point (some 10 years ago). It was:

atomicReadRef(x) = atomicRead(x) + 1;

But it's painfully obvious that yes the intent is to read the address
and read the thing... so why need these anyway? So we left things as
they are.

I agree shared needs work, but this is not it. We're wasting our time here.

Hey, that's fine. I'd rather work on other things too. Shared just seems like an unfulfilled promise, with half-implemented protections.

I'd like to just see shared be unusable, and make people cast away shared to do anything. That at least is an attempt at preventing races without intention. The allowance of certain things that are obvious races, whereas other things that are obvious races are prevented makes one assume the worst.

-Steve

Reply via email to