www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - synchronized/shared associative array .require error

reply cc <cc nevernet.com> writes:
```d
synchronized class SyncTable(KEY, VAL) {
	private VAL[KEY] table;
	auto require(KEY key) {
		return table.require(key);
	}
}

auto table = new shared SyncTable!(string, string);
table.require("abc");
```

Fails to compile:
```
// Error: none of the overloads of template `object.require` are 
callable using argument types `!()(shared(string[string]), 
string)`
```

Tried casting away shared as a workaround but I assume that will 
cause some kind of TLS catastrophe.
Sep 02 2022
next sibling parent reply Loara <loara noreply.com> writes:
On Friday, 2 September 2022 at 19:15:45 UTC, cc wrote:
 ```d
 synchronized class SyncTable(KEY, VAL) {
 	private VAL[KEY] table;
 	auto require(KEY key) {
 		return table.require(key);
 	}
 }

 auto table = new shared SyncTable!(string, string);
 table.require("abc");
 ```

 Fails to compile:
 ```
 // Error: none of the overloads of template `object.require` 
 are callable using argument types `!()(shared(string[string]), 
 string)`
 ```

 Tried casting away shared as a workaround but I assume that 
 will cause some kind of TLS catastrophe.
In current version of D language `synchronized` and `shared` are independent. In particular `shared` should be used only for basic types like integers for which atomic operations are well defined, and not for classes. Anyway if you must send a reference of a `synchronized` class to a different thread then it's safe to cast `shared` and then remove it later: ```d synchronized class A{ ... } void sendTo(Tid to, A a){ to.send(cast(shared A) a); } A receiveA(){ A a; receive( (shared A sa) { a = cast(A) sa; }); return a; } ``` Unfortunately there isn't any traits that tells you if a class is `synchronized` or not, so you can't do a safe template function for this.
Sep 03 2022
parent reply frame <frame86 live.com> writes:
On Saturday, 3 September 2022 at 09:49:54 UTC, Loara wrote:

 In current version of D language `synchronized` and `shared` 
 are independent. In particular `shared` should be used only for 
 basic types like integers for which atomic operations are well 
 defined, and not for classes.
Not exactly, a synchronized class member function becomes automatically a shared one.
Sep 03 2022
parent reply Loara <loara noreply.com> writes:
On Saturday, 3 September 2022 at 14:07:58 UTC, frame wrote:
 Not exactly, a synchronized class member function becomes 
 automatically a shared one.
This is not present in official documentation so other compilers different from `dmd` aren't forced to assume it. This should be consider an experimental feature of D that users should be able to turn off if they want.
Sep 06 2022
parent frame <frame86 live.com> writes:
On Tuesday, 6 September 2022 at 10:28:53 UTC, Loara wrote:
 On Saturday, 3 September 2022 at 14:07:58 UTC, frame wrote:
 Not exactly, a synchronized class member function becomes 
 automatically a shared one.
This is not present in official documentation so other compilers different from `dmd` aren't forced to assume it. This should be consider an experimental feature of D that users should be able to turn off if they want.
Hmm.. LDC does the same to me. I think the whole synchronization class is an experimental feature :D
Sep 06 2022
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/2/22 3:15 PM, cc wrote:

 Tried casting away shared as a workaround but I assume that will cause 
 some kind of TLS catastrophe.
 
I think it will be fine, but you may have an issue. You are returning a non-shared `VAL`, but your class is `shared`, which means `table`, and all the `VAL` and `KEY` inside must also be `shared`. If you cast away `shared` you have to put it back upon return. TLS should not be involved here at all, so there is no problem there. -Steve
Sep 03 2022
parent reply cc <cc nevernet.com> writes:
On Saturday, 3 September 2022 at 14:37:16 UTC, Steven 
Schveighoffer wrote:
 On 9/2/22 3:15 PM, cc wrote:

 Tried casting away shared as a workaround but I assume that 
 will cause some kind of TLS catastrophe.
 
I think it will be fine, but you may have an issue. You are returning a non-shared `VAL`, but your class is `shared`, which means `table`, and all the `VAL` and `KEY` inside must also be `shared`. If you cast away `shared` you have to put it back upon return. TLS should not be involved here at all, so there is no problem there. -Steve
Alright, so this is safe then? ```d alias VAL[KEY] T; auto require(KEY key) { auto unsharedT = cast(T) table; auto r = unsharedT.require(key); table = cast(shared) unsharedT; return cast(shared) r; } ``` Was a bit surprised to see mutating `unsharedT` left `table` unchanged and needed reassigning.
Sep 04 2022
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/4/22 11:24 PM, cc wrote:
 On Saturday, 3 September 2022 at 14:37:16 UTC, Steven Schveighoffer wrote:
 On 9/2/22 3:15 PM, cc wrote:

 Tried casting away shared as a workaround but I assume that will 
 cause some kind of TLS catastrophe.
I think it will be fine, but you may have an issue. You are returning a non-shared `VAL`, but your class is `shared`, which means `table`, and all the `VAL` and `KEY` inside must also be `shared`. If you cast away `shared` you have to put it back upon return. TLS should not be involved here at all, so there is no problem there.
Alright, so this is safe then? ```d alias VAL[KEY] T; auto require(KEY key) {     auto unsharedT = cast(T) table;     auto r = unsharedT.require(key);     table = cast(shared) unsharedT;     return cast(shared) r; } ```
I think that is fine-ish. You still don't have a shared `KEY` there. But it really depends on what KEY is. Most likely it's fine (e.g. if `KEY` is string). If you don't ever really fetch anything out of the key, and just use it to map to your values, I think it should be fine.
 Was a bit surprised to see mutating `unsharedT` left `table` unchanged 
 and needed reassigning.
Yes, because before an AA contains an element, it is a `null` AA. When you add the first element, it's allocated. When you make a copy of a `null` AA, it doesn't affect the original. You can fix this by reinterpret casting the AA instead of copying it: ```d auto r = .require(*(cast(T*)&table), key); // I think this might also work: auto r = (cast()table).require(key); ``` -Steve
Sep 05 2022