digitalmars.D - Shared method problem
- tcak (57/57) Feb 12 2014 Whenever I start writing a class which would support "shared"
- Stanislav Blinov (28/31) Feb 12 2014 Exactly. Separate implementations. Completely. Shared is not just
- Andrei Alexandrescu (4/12) Feb 12 2014 Yah, disallowing code sharing is an intentional limitation of "shared".
- Stanislav Blinov (3/5) Feb 12 2014 Don't forget to emphasize this in second edition of TDPL :D
- tcak (10/43) Feb 12 2014 The thing is I have written many threaded applications in the
Whenever I start writing a class which would support "shared" methods, either there are lots of duplicate methods come into class, synchronisation code required. PROBLEM 1: Duplication Look at the code below: class NamedPipe{ private string filename; private int mode; public this(string filename, int mode){ // cast is used to fix `shared` problem this.filename = cast( typeof(this.filename) )filename; this.mode = cast( typeof(this.mode) )mode; } } If I define the constructor WITHOUT "shared" keyword, and try to create a shared object as `auto pipe = new shared NamedPipe("/tmp/pipe", 432);`, compiler tells me, I can't do this with shared keyword. If I define the constructor WITH "shared" keyword, and try to create a non-shared object, again compiler gives error. So, it is pushing me to either duplicate constructor or do casting. Some of you may say `pure` function etc., though if you are writing a complex class, that may not be possible. So, duplication is inevitable. PROBLEM 2: Synchronisation Let's say I want to write a method that will do synchronisation ONLY IF the method is called from a shared object. public void updateMode( int newMode ){ // THIS IS NOT SHARED. CHANGE IT IMMEDIATELY. mode = newMode; } public void updateMode( int newMode ) shared{ // THIS IS SHARED. SYNCHRONISE WHILE CHANGING. synchronized( this ){ mode = newMode; } } The above code is good, but same method is duplicated again just to be able to enable synchronisation on shared method. So, non-shared method can run at much higher speed if it is to be called so many times. CONCLUSION: In the current implementation, duplication is almost inevitable, and if codes are long, then God help us. Long maintenance and error prone coding. To be able to solve this, I thought a coding style as below: public void foo(){ static if( is(this: shared) ){ // some of codes come here if the object is shared } else{ // some of codes come here if the object is not shared } } But unfortunately it doesn't work in this way. Is there really need to allow shared objects different methods, and non-shared objects different methods? Why don't we separate implementation instead of methods according to being shared?
Feb 12 2014
To be concise: don't put all your eggs into one basket. If you want shared class - write shared class.Is there really need to allow shared objects different methods, and non-shared objects different methods? Why don't we separate implementation instead of methods according to being shared?Exactly. Separate implementations. Completely. Shared is not just about "insert synchronized everywhere and be done with it". As a storage class, it tells the compiler "don't reorder accesses to this variable". Yes, as method attribute, it disallows you to call this method on an unshared reference. But that doesn't mean you now should rush to create both shared and non-shared methods for your classes: you'll be doing yourself a disservice. Design and implementation of concurrent data structures is very different from non-concurrent ones. Look up any concurrent data structure and see how drastically it differs from the plain, "single-threaded" one, even if it's built on lock-based synchronization, let alone lock-free. Providing two different implementations (that require different data for e.g. bookkeeping) inside one class is impractical and error-prone. If you're just going to synchronize every single method call for your class on a mutex, then you don't really need shared qualifier at all (well, you'll need to briefly cast the reference to shared to e.g. pass it to another thread). Also, I assume you understand that 'shared' and all its aspects are not yet fully realized in the language. Andrei mentioned that finalizing 'shared' should be made one of the primary goals. Maybe we would see some interesting syntactic solutions, type system improvements, etc. I think we already can help with some things (see e.g. my thread about shared sync primitives). But regardless, design your single-threaded and concurrent data separately, go easy on yourself :)
Feb 12 2014
On 2/12/14, 6:00 AM, Stanislav Blinov wrote:To be concise: don't put all your eggs into one basket. If you want shared class - write shared class.Yah, disallowing code sharing is an intentional limitation of "shared". I'm glad that works :o). AndreiIs there really need to allow shared objects different methods, and non-shared objects different methods? Why don't we separate implementation instead of methods according to being shared?Exactly. Separate implementations. Completely. Shared is not just about "insert synchronized everywhere and be done with it". As a storage class, it tells the compiler "don't reorder accesses to this variable".
Feb 12 2014
On Wednesday, 12 February 2014 at 16:25:35 UTC, Andrei Alexandrescu wrote:Yah, disallowing code sharing is an intentional limitation of "shared". I'm glad that works :o).Don't forget to emphasize this in second edition of TDPL :D
Feb 12 2014
On Wednesday, 12 February 2014 at 14:00:19 UTC, Stanislav Blinov wrote:To be concise: don't put all your eggs into one basket. If you want shared class - write shared class.The thing is I have written many threaded applications in the webserver and web app framework in December 2012 in D2. It works at the same performance of Apache and never seen any problem yet, and still works. Though problem is that while D is preventing many mistakes in code with this shared keyword, it tired me more than other languages, and I just wanted share my thoughts about it.Is there really need to allow shared objects different methods, and non-shared objects different methods? Why don't we separate implementation instead of methods according to being shared?Exactly. Separate implementations. Completely. Shared is not just about "insert synchronized everywhere and be done with it". As a storage class, it tells the compiler "don't reorder accesses to this variable". Yes, as method attribute, it disallows you to call this method on an unshared reference. But that doesn't mean you now should rush to create both shared and non-shared methods for your classes: you'll be doing yourself a disservice. Design and implementation of concurrent data structures is very different from non-concurrent ones. Look up any concurrent data structure and see how drastically it differs from the plain, "single-threaded" one, even if it's built on lock-based synchronization, let alone lock-free. Providing two different implementations (that require different data for e.g. bookkeeping) inside one class is impractical and error-prone. If you're just going to synchronize every single method call for your class on a mutex, then you don't really need shared qualifier at all (well, you'll need to briefly cast the reference to shared to e.g. pass it to another thread). Also, I assume you understand that 'shared' and all its aspects are not yet fully realized in the language. Andrei mentioned that finalizing 'shared' should be made one of the primary goals. Maybe we would see some interesting syntactic solutions, type system improvements, etc. I think we already can help with some things (see e.g. my thread about shared sync primitives). But regardless, design your single-threaded and concurrent data separately, go easy on yourself :)
Feb 12 2014