-
-
Notifications
You must be signed in to change notification settings - Fork 423
assumeLocal: convert shared lvalue to a non-shared one #724
Conversation
src/core/atomic.d
Outdated
/** | ||
* Converts a shared lvalue to a non-shared lvalue. | ||
* | ||
* As the name suggests, this functions allows to treat a shared lvalue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kill off the As the name suggests
part please (we're aiming for objective documentation). :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this doesn't support classes it should document this. But why doesn't it support classes? That too should be documented.
Something is wrong here. Why do you make something shared if it's protected by a mutex? |
Consider member variables inside a It's true that accessing the variable outside of the lock will be erroneous, but this function is a convenience for cases when such access is not needed. See e.g. my ongoing branch implementing Some kind of workaround is needed. Lots of casts or chains of raw atomicLoad/Store calls IMO are inferior to this little helper. |
What's with automatic HeadUnshared for synchronized classes? I don't want to slow down you efforts to make core.sync shared and I think |
Even if it were implemented in that exact wording, it would be of little help in many cases. I know that in the grand scheme,
I know, that is my thread :)
I'm trying to. |
src/core/atomic.d
Outdated
@@ -1090,6 +1136,13 @@ if(__traits(isFloating, T)) | |||
} | |||
} | |||
|
|||
// assumeLocal is architecture-independent: it is just a cast | |||
ref auto assumeLocal(T)( ref shared T val ) @trusted pure nothrow | |||
if( !is( T == class ) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!is(T == class))
Fine, but let's call it |
Take that back, should be |
ping |
+1 for |
I apologize for so long an absence, got caught up in a no-D world. So, rename to |
yes please |
Ping |
@radcapricorn any chance to revive this? Seems like non-controversial stuff that just fell off the radar. |
Ping @radcapricorn ? |
Three years >< |
src/core/atomic.d
Outdated
ref T assumeUnshared(T)(ref shared T val) @system @nogc pure nothrow | ||
if(!is(T == class) && !is(T == interface)) | ||
{ | ||
return *cast(T*)&val; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space after close paren in cast
* Returns: | ||
* The non-shared lvalue. | ||
*/ | ||
ref immutable(T) assumeUnshared(T)(ref immutable(T) val) @safe @nogc pure nothrow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be a use case for this? It doesn't change the type of its argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generic code.
shared struct Example(T)
{
private T payload;
T getUnsharedCopyOfPayload() const
{
return payload.assumeUnshared;
}
}
auto createExample(T)(auto ref T value)
{
return shared(Example!T)(value);
}
immutable int i = 42;
auto example = createExample(i);
assert(is(typeof(example.getUnsharedCopyOfPayload()) == immutable(int));
This way, Example doesn't have to specialize such use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IOTW, it's safe to assume immutable as unshared. But the signature ref T assumeUnshared(T)(ref shared T val)
will not accept immutable lvalue, hence the specialization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
immutable
is actually implicitly shared
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, and assumeUnshared
should accept shared arguments, therefore it shouldn't fail to compile with immutable argument. It works as advertised: takes shared lvalue and yields lvalue that can be treated as unshared. It just so happens that immutable is both at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andralex @radcapricorn anything else still not clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still unconvinced about the usefulness. By that logic we should also define assumeUnshared
for regular data so assumeUnshared
works transparently with all data types (after all unshared data can be assumed to be unshared!)
One possibility is to not introduce this overload yet, and see how necessary it is in practice.
At any rate, if we do introduce the overload the documentation must be merged with the other overload's.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good addition. A few nits need fixing.
ref T assumeUnshared(T)(ref shared T val) @system @nogc pure nothrow | ||
if(!is(T == class) && !is(T == interface)) | ||
{ | ||
return *cast(T*) &val; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the ddoc version, right? Then it should not have an implementation.
* Returns: | ||
* The non-shared lvalue. | ||
*/ | ||
ref immutable(T) assumeUnshared(T)(ref immutable(T) val) @safe @nogc pure nothrow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still unconvinced about the usefulness. By that logic we should also define assumeUnshared
for regular data so assumeUnshared
works transparently with all data types (after all unshared data can be assumed to be unshared!)
One possibility is to not introduce this overload yet, and see how necessary it is in practice.
At any rate, if we do introduce the overload the documentation must be merged with the other overload's.
@@ -1290,6 +1357,19 @@ if(__traits(isFloating, T)) | |||
} | |||
} | |||
|
|||
// assumeUnshared is architecture-independent: it is just a cast | |||
ref auto assumeUnshared(T)(ref shared T val) @system @nogc pure nothrow | |||
if(!is(T == class) && !is(T == interface)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
obey phobos, if
flush to the left and space after it
Revived this to #2156 |
This is one of the two functions to satisfy ER 12133 - Relaxed read-modify-write for shared lvalues.