Jump to page: 1 2
Thread overview
why can't I call const methods on shared objects?
May 09, 2014
Vlad Levenfeld
May 09, 2014
Vlad Levenfeld
May 09, 2014
Vlad Levenfeld
May 09, 2014
Vlad Levenfeld
May 09, 2014
Vlad Levenfeld
May 09, 2014
Vlad Levenfeld
May 10, 2014
Vlad Levenfeld
May 11, 2014
monarch_dodra
May 11, 2014
FreeSlave
May 11, 2014
FreeSlave
May 11, 2014
John Colvin
May 13, 2014
Vlad Levenfeld
May 09, 2014
Error: non-shared const method is not callable using a shared mutable object

Why not? If the method is const, it can't modify the object anyway.
May 09, 2014
On Fri, 09 May 2014 17:37:35 -0400, Vlad Levenfeld <vlevenfeld@gmail.com> wrote:

> Error: non-shared const method is not callable using a shared mutable object
>
> Why not? If the method is const, it can't modify the object anyway.

Non-shared methods cannot be called on shared objects. Otherwise, you could have unintended race conditions.

-Steve
May 09, 2014
Is this still the case if the method is const or pure?
May 09, 2014
Is there any way to declare a method as "safe regardless of shared/mutability/etc" (or some other way to avoid cast(Type)object.property every time I want to check a property which won't affect any state)?
May 09, 2014
I mean I thought that's what "pure" was for but the compiler complains all the same.
May 09, 2014
On Fri, 09 May 2014 17:45:37 -0400, Vlad Levenfeld <vlevenfeld@gmail.com> wrote:

> Is there any way to declare a method as "safe regardless of shared/mutability/etc" (or some other way to avoid cast(Type)object.property every time I want to check a property which won't affect any state)?

Not really for shared. For everything else, there's const for value properties, and inout for reference properties.

Shared is quite different, because the method has to be cognizant of race conditions. It has to be implemented differently.

Casting away shared is somewhat dangerous, but OK if you logically know there is no race condition.

-Steve
May 09, 2014
Let me see if I understand this right... let's say I have some (unshared) class that launches threads to do its real work in.

class Foo {
  this () {thread = spawn (&work);}
  shared void work () {...};
  void send_message (T) (T msg) {thread.send (msg);}
  Tid thread;
}

It has an unshared method to pass messages to the worker thread, and everything is copacetic, but what is the best practice for when I want another thread to interact with one of these instances?

class Bar {
  this () {thread = spawn (&pass);}
  shared void pass () {
    receive (
       (shared Foo F) {this.F = F;}                  // (1)
       (T msg) {(cast(Foo)F).send_message (msg);},   // (2)
    );
  void send_message (T) (T msg) {thread.send (msg);}
  Tid thread;
  Foo F;
}

void main () {
  auto F = new Foo;
  auto B = new Bar;
  B.send_message (cast(shared)F);                    // (3)
  // sleep
}

When I interact with F from at (1), this.F is automatically shared (because Bar is shared) so this compiles. Here, this.F refers to the same F I would refer to if I accessed this.F from the main method, it just gets automatically shared whenever Bar is shared. So when I spawn a worker thread, the worker thread sees a shared Bar (and shared F), while the main thread sees a Bar that it owns, but they are both looking at the same Bar (just with different access rules, like a const and non-const reference to the same object).
At (2), I have to cast F to unshared in order to send it a message. But this is ok, because I am only sending messages, and am not risking a race condition. Basically I am announcing "I know that multiple threads can see this, but I am taking ownership of it and taking responsiblity for preventing races."
And when I cast to shared at (3), I am announcing "I am explicitly recognizing that multiple threads may now access this, and that there is a potential for races."

Is this the right way to handle this situation?

And on a more general note, the shared keyword, as I understand it, is intended to be a sort of compiler-reinforced tag that I can use to prevent races the same way const helps prevent unintended side-effects, and  to aid my reasoning when I do need to debug a race?
May 09, 2014
PS After reading your post I experimented with overloading shared/unshared methods in my code and came up with this solution:

shared Id!Service id ()() const if (is (typeof(this) == shared)) {
  return (cast(Service)this).id;
}
Id!Service id () const {
  return service_id;
}

I like this better than casting at the callsite (though it would be nice to roll those two into one method using a static if somehow, but I can't think of any way to do this).
May 10, 2014
aaand on further experimentation it turns out I don't need a template at all, I can just overload it... strange, I seem to remember not being able to do that before.
May 11, 2014
On Friday, 9 May 2014 at 21:42:14 UTC, Vlad Levenfeld wrote:
> Is this still the case if the method is const or pure?

Const methods still require synchronization, because other threads may change some data, needed by const method while method is executed, and then you may get wrong results.

Consider:

class Point
{
public:
    float x;
    float y;


}
« First   ‹ Prev
1 2