digitalmars.D.learn - Passing shared delegates
- Martin Drasar (16/36) Jan 11 2013 I get this error:
- mist (7/7) Jan 11 2013 Do not have time to test code right now but first guess it is
- =?UTF-8?B?TWFydGluIERyYcWhYXI=?= (5/17) Jan 13 2013 Hi mist,
- Maxim Fomin (11/35) Jan 13 2013 Which compiler version do you use? It compiles on 2.061.
- Martin Drasar (4/18) Jan 14 2013 Thanks for clarification.
- mist (3/6) Jan 14 2013 Yes, it was a known bug in pre-2.061
- Martin Drasar (9/43) Jan 16 2013 If I uncomment that line I get this error:
- Maxim Fomin (11/26) Jan 16 2013 Yes, it happens so (shared function made it a member). Casting
- Martin Drasar (20/30) Jan 17 2013 Ok. But that leaves me with an unanswered question from one of my
- Maxim Fomin (66/83) Jan 17 2013 Casting away shared in undefined behavior. Although it may be not
- Martin Drasar (9/28) Jan 17 2013 I know about some peculiarities of shared (this thread
Hi, when trying to compile this code:module main; class A { shared void foo() {} } class B { void bar(shared void delegate() f) {} } void main() { auto a = new A(); auto b = new B(); b.bar(&a.foo); }I get this error:main.d(18): Error: cannot implicitly convert expression (&a.foo) of type void delegate() shared to shared(void delegate())I have searched the bugzilla and newsgroups and found various threads related to shared and delegate passing and the most recent was about casting it all away and then back in when needed. Is this the only possible way to do it? In my program I want to pass delegates to a running thread using std.concurrency. I can do it by casting the delegate (or rather a structure containing the delegate together with other stuff) to shared, send it, cast it away after I receive it and then work with it. But that does not feel right... What exactly happens when I cast to and from shared? Does the object get copied, moved, or any other magic? Is it costly operation? Thanks for any hints, Martin
Jan 11 2013
Do not have time to test code right now but first guess it is related to parsing differences for delegates and usual functions. Delegates can have shared/const applied to both delegate type itself and context of underlying function. Those are different beasts and no wonder type system complains. You may need to try something like "void delegate() shared f" if you want delegate type to match method one.
Jan 11 2013
Dne 11.1.2013 23:26, mist napsal(a):Do not have time to test code right now but first guess it is related to parsing differences for delegates and usual functions. Delegates can have shared/const applied to both delegate type itself and context of underlying function. Those are different beasts and no wonder type system complains. You may need to try something like "void delegate() shared f" if you want delegate type to match method one.Hi mist, that was the first thing I tried, but it resulted in a completely different error:class B { void bar(void delegate() shared f) {} }Error: const/immutable/shared/inout attributes are only valid for non-static member functionsMartin
Jan 13 2013
On Monday, 14 January 2013 at 07:20:17 UTC, Martin DraĊĦar wrote:Dne 11.1.2013 23:26, mist napsal(a):Which compiler version do you use? It compiles on 2.061. In case of applying attributes to functions, mostly it is irrelevant whether it stands first or last. So, void foo() shared {} and shared void foo() {} in A class are equivalent. However in case of bar parameter you are qualifying not a function, but object, so shared before return type of delegate applies to object, like (shared (int i)). Shared after delegate applies to delegate type, not object itself.Do not have time to test code right now but first guess it is related to parsing differences for delegates and usual functions. Delegates can have shared/const applied to both delegate type itself and context of underlying function. Those are different beasts and no wonder type system complains. You may need to try something like "void delegate() shared f" if you want delegate type to match method one.Hi mist, that was the first thing I tried, but it resulted in a completely different error:class B { void bar(void delegate() shared f) {} }Error: const/immutable/shared/inout attributes are only valid for non-static member functionsMartin
Jan 13 2013
On 14.1.2013 8:56, Maxim Fomin wrote:Which compiler version do you use? It compiles on 2.061.It was 2.060. It compiles now on 2.061. Great!In case of applying attributes to functions, mostly it is irrelevant whether it stands first or last. So, void foo() shared {} and shared void foo() {} in A class are equivalent. However in case of bar parameter you are qualifying not a function, but object, so shared before return type of delegate applies to object, like (shared (int i)). Shared after delegate applies to delegate type, not object itself.Thanks for clarification. Martin
Jan 14 2013
On Monday, 14 January 2013 at 10:13:16 UTC, Martin Drasar wrote:On 14.1.2013 8:56, Maxim Fomin wrote:Yes, it was a known bug in pre-2.061 Big relief to have it working :)Which compiler version do you use? It compiles on 2.061.It was 2.060. It compiles now on 2.061. Great!
Jan 14 2013
Okay, I have hit another thing when dealing with shared delegates. Consider this code:alias void delegate (B b) shared Callback; class A { private B _b; this (B b) { _b = b; } void callback (B b) shared { b.execute(&callback); //_b.execute(&callback); <-- Uncomment this for error } } class B { void execute (Callback c) { c(this); } } void main() { auto b = new B(); auto a = new A(b); b.execute(&a.callback); }If I uncomment that line I get this error:Error: function main.B.execute (void delegate(B b) shared c) is not callable using argument types (void delegate(B b) shared) sharedThis error probably appears because typeof b is B and typeof _b is shared(B). My question is - why? Is it a bug or does the shared delegate made it shared and it is ok? And what to do with it? I can cast away shared of _b, but is it a correct and clean way? Thanks for your input. Martin
Jan 16 2013
On Wednesday, 16 January 2013 at 20:05:40 UTC, Martin Drasar wrote:Okay, I have hit another thing when dealing with shared delegates. If I uncomment that line I get this error:Yes, it happens so (shared function made it a member). Casting away shared is UB but it can be done if your are sure. Consider rewriting the code and eliminating unnecessary shareds and please stop attaching "> " to each line of code. To workaround add another method: void callback(B b) { _b.execute(&callback); }Error: function main.B.execute (void delegate(B b) shared c) is not callable using argument types (void delegate(B b) shared) sharedThis error probably appears because typeof b is B and typeof _b is shared(B). My question is - why? Is it a bug or does the shared delegate made it shared and it is ok? And what to do with it? I can cast away shared of _b, but is it a correct and clean way? Thanks for your input. Martin
Jan 16 2013
On 16.1.2013 22:53, Maxim Fomin wrote:Yes, it happens so (shared function made it a member). Casting away shared is UB but it can be done if your are sure.Ok. But that leaves me with an unanswered question from one of my previous posts. What happens when you cast from and to shared? Is there any moving in memory from TLS and back? Or does it just access the memory as if it were in shared space? I have tried to compare addresses of b and _b, but writeln refuses to display an address of shared and assert does not help me either. But using the inspection capabilities of VisualD I found out that they seem to have the same address.Consider rewriting the code and eliminating unnecessary shareds andI am afraid that the original code has as little shareds as possible. But I have an idea how to rewrite it to avoid needing to access _b.please stop attaching "> " to each line of code.Sorry about that. It is a habit that prevents Thunderbird from linewrapping a code. If you have Thunderbird on receiving end then it is no problem - you can copy the quoted code without those '>'. But I understand that with other clients it might be irritating.To workaround add another method: void callback(B b) { _b.execute(&callback); }Yes, that could help. But as I wrote before, I will rewrite it to avoid this issue. Thanks, Martin
Jan 17 2013
On Thursday, 17 January 2013 at 08:46:22 UTC, Martin Drasar wrote:Ok. But that leaves me with an unanswered question from one of my previous posts.Casting away shared in undefined behavior. Although it may be not written explicitly in dlang.org, once D will have a standard like C or C++, it will be name like so. In practice this means that behavior of program is uncertain and may result in many consequences. In this case content of arrays may be any of 1,2,3,4,5,6. import std.concurrency : spawn; import std.stdio : writeln; shared int[] arr1; shared int[] arr2; static this() { arr1.length = arr2.length = 100; foreach(ref e; arr1) { e = 1; } foreach(ref e; arr2) { e = 2; } } void thread1() { int[] arr_1 = cast(int[])arr1; int[] arr_2 = cast(int[])arr2; arr_2[] = 3; arr_1[] = 4; } void thread2() { int[] arr_1 = cast(int[])arr1; int[] arr_2 = cast(int[])arr2; arr_2[] = 5; arr_1[] = 6; } void main() { spawn(&thread1); spawn(&thread2); writeln(arr1); writeln(arr2); } Note, if you mark functions as safe, the code will not compile, because throwing shared is not allowed in D safe code.What happens when you cast from and to shared? Is there any moving in memory from TLS and back? Or does it just access the memory as if it were in shared space?It is implementation specific, but I guess nothing is moved, just a variable is reinterpreted.I have tried to compare addresses of b and _b, but writeln refuses to display an address of shared and assert does not help me either. But using the inspection capabilities of VisualD I found out that they seem to have the same address. Thanks, Martinimport core.stdc.stdio : printf; import std.concurrency; int a; __gshared int b; shared int c; void thread() { printf("%p=%d\n%p=%d\n%p=%d\n", &a, a, &b, b, &c, c); } void main() { c = a = 2; spawn(&thread); printf("%p=%d\n%p=%d\n%p=%d\n", &a, a, &b, b, &c, c); } You can compile this code and look at addresses and assembly if you are interested in implementation details.
Jan 17 2013
On 17.1.2013 12:56, Maxim Fomin wrote:Casting away shared in undefined behavior. Although it may be not written explicitly in dlang.org, once D will have a standard like C or C++, it will be name like so. In practice this means that behavior of program is uncertain and may result in many consequences. In this case content of arrays may be any of 1,2,3,4,5,6. ... snip ... Note, if you mark functions as safe, the code will not compile, because throwing shared is not allowed in D safe code.I know about some peculiarities of shared (this thread http://forum.dlang.org/thread/k7orpj$1tt5$1 digitalmars.com was a good eye-opener) and tend to avoid it as much as possible and solve my problems with message passing concurrency, however there are some times when I had to do some casting and just be careful.Ok, good.What happens when you cast from and to shared? Is there any moving in memory from TLS and back? Or does it just access the memory as if it were in shared space?It is implementation specific, but I guess nothing is moved, just a variable is reinterpreted.... snip ... You can compile this code and look at addresses and assembly if you are interested in implementation details.Good ol' printf. I should have thought about it. Thanks. Martin
Jan 17 2013