On Friday, 1 February 2013 at 04:22:51 UTC, Zach the Mystic wrote:
On Friday, 1 February 2013 at 03:39:19 UTC, TommiT wrote:
On Friday, 1 February 2013 at 03:13:42 UTC, Zach the Mystic
wrote:
On Friday, 1 February 2013 at 02:27:30 UTC, TommiT wrote:
And here's another example of why it is as big of a problem
as I make it sound to be:
import std.concurrency;
struct Array
{
int _len;
length struct // Using Zach's syntax
{
@property get() { return _len; }
alias this = get;
void opAssign(int rhs) { _len = rhs; }
}
}
void func(T)(T t)
{
auto v = t;
v = 10;
}
void main()
{
Array arr;
spawn(&func!int, arr.length);
arr.length = 20; // And here we have a data-race.
// Good luck trying to find these
// kinds of bugs.
}
I'm sorry, I know very little about race conditions. If you
might explain just a little bit about what is happening here,
I'd be in a better position to understand what you're saying.
I really can't say anything other than please describe what
this does and why it's a problem at this time.
spawn(&func!int, arr.length);
...creates a new thread and runs the following function call
in it:
func!(int)(arr.length)
While that function call is evaluating in the new thread, the
old thread may simultaneosly execute:
arr.length = 20;
Since both of those threads end up at some point calling
arr.length.opAssign and therefore both of them may assign to
arr._len simultaneously, that's a data-race. It would be
data-race also if only one of them wrote to it and the other
one just read it.
I'm familiar with the fact that programmers face endless woes
with regard to data-races. I thought that D has unshared data
by default. But since Array arr is defined in main instead of
outside main, therefore it is sharable between the two threads?
If two threads have access to the same data, what makes length
as a property different from length as an int? This problem may
be over my head for now...
Actually, that example of mine was wrong - it's not a data-race.
I failed to notice that in:
spawn(&func!int, arr.length);
...arr.length is actually converted to int using alias this. My
bad.
Now I'm going to repeat the "spooky modification at a distance"
problem I showed earlier, but this time, instead of writing it in
the new syntax and the new struct behaviour you invented, I write
it using current D syntax:
import std.concurrency;
struct Array
{
int _len;
struct PropType
{
Array* _outer; // In your syntax this was implicit
@property int get()
{
return _outer._len;
}
alias this = get;
void opAssign(int rhs)
{
_outer._len = rhs;
}
}
PropType length;
}
void func(T)(T t)
if (isImplicitlyConvertible!(T,int))
{
// Given that is(T == Array.PropType), then
// all 3 lines below do the same thing:
t = 42;
t.opAssign(42);
t._outer._len = 42;
}
void main()
{
Array arr;
// setting the _outer pointer to the enclosing object:
arr.length._outer = &arr;
assert(arr._len == 0);
func(arr.length); // no conversion to int happening here
assert(arr._len == 42);
}
So, it's possible to modify arr._len just by passing arr.length
by value to a function.