On 25.09.2011 04:25, Peter Alexander wrote:
On 24/09/11 4:47 PM, Rainer Schuetze wrote:
Sorry for the bad example, here's one that is not thread-safe, and where
the invariant can fail in a multi-threaded environment:
shared(int) globId;
class C
{
invariant() { assert((globId & 1) == 0); }
@property int id() immutable
{
globId = globId + 1;
globId = globId + 1;
return globId;
}
}
But the details whether the operation happens to be thread safe or not
is irrelevant, thread-safety is not guaranteed by the type system with
immutable.
It's still thread safe! I think you are misunderstanding what thread
safety is.
http://en.wikipedia.org/wiki/Thread_safety
You are right in saying that the invariant may break, but that doesn't
prove that the code isn't thread safe, it just proves that you have a
bad invariant. You may as well have written:
invariant() { assert(false); }
and then claimed that the code wasn't thread safe because immutable
didn't save you.
Grrr, another bad example, where some bad side-effects did not get
unnoticed ;-)
Thread safety in your example simply means that calling id() 10 times
from different threads will always result in globId == 20 at the end.
This isn't guaranteed by many languages.
This is what I wanted to show: it is also not guaranteed in D. Checking
the disassembly there is nothing atomic about the operations. Even
++globId does not use a locked increment.
Thread safety does *not* guarantee that your invariant will hold,
because your invariant not only requires thread safety but mutually
exclusive access to globId around calls to id().
I should point out that immutable has absolutely no bearing in your
example. Having immutable methods in a class with no members means
nothing! The thread-safety comes from the shared(int) here.
Which finally brings us back to the original question: What does
immutable guarantee in the face of non-pure property getter functions?