digitalmars.D.learn - Singleton Pattern with struct
- ParticlePeter (31/31) Jan 24 2013 Hi,
- Maxim Fomin (26/57) Jan 24 2013 Even if Singleton.instance returns by ref, s object is still
- Jacob Carlborg (4/7) Jan 24 2013 The struct is allocated using "new".
- Maxim Fomin (8/14) Jan 24 2013 This is about "auto s = " in main, not about "new" in method.
- ParticlePeter (10/10) Jan 24 2013 Got it, thanks, I changed the instance method to:
- Maxim Fomin (26/36) Jan 24 2013 Yes, but this can be broken by:
- Era Scarecrow (24/35) Jan 24 2013 I'm not sure but this seems like one of the few appropriate
- Maxim Fomin (3/39) Jan 24 2013 I agree, but disabling ctors makes creating module-level object
- Era Scarecrow (15/34) Jan 24 2013 I'll have to agree. But in that case don't disable the default
- ParticlePeter (13/38) Jan 24 2013 O.k. good to know, I'll try to avoid this. But one thing is still
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (17/28) Jan 24 2013 When you print the type of another_s you will see that it is not a ref,
- Maxim Fomin (6/38) Jan 24 2013 Actually the caller gets the reference (which is a pointer from
- ParticlePeter (10/42) Jan 24 2013 Thanks, I re-read the purpose of ref type function() in the D
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (26/35) Jan 24 2013 As Maxim Fomin noted, I didn't word it correctly: The caller does get a
- ParticlePeter (14/56) Jan 24 2013 This is what I meant :-) I can't return a reference ( with
- Artur Skawina (24/69) Jan 24 2013 There currently are no reference variables in D [1]; the only way to get
- ParticlePeter (5/82) Jan 24 2013 Well ... I think I as well would not wanna do it like this,
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (8/10) Jan 24 2013 With the exception that the -> operator is replaced by the dot operator
- Artur Skawina (6/36) Jan 24 2013 Careful, at some point you'll end up doing s[1] etc, and /then/ it matte...
- Artur Skawina (5/22) Jan 24 2013 Grr. What I meant to write was of course:
- ParticlePeter (8/11) Jan 24 2013 But where and when is ( a second ? ) Singleton created or
Hi, I am trying to figure out the singleton pattern with a struct instead of a class: [code] struct Singleton { private : this( int a = 0 ) {} ; static Singleton * s ; public : disable this() ; static ref Singleton instance() { if ( s is null ) s = new Singleton( 0 ) ; return * s ; } int val = 0 ; } [/code] This compiles, but when I use it: [code] auto s = Singleton.instance ; writeln( s.val ) ; Singleton.instance.val = 2 ; writeln( s.val ) ; [/code] I get: 0 0 Where is my mistake ? Cheers, PP !
Jan 24 2013
On Thursday, 24 January 2013 at 14:11:10 UTC, ParticlePeter wrote:Hi, I am trying to figure out the singleton pattern with a struct instead of a class: [code] struct Singleton { private : this( int a = 0 ) {} ; static Singleton * s ; public : disable this() ; static ref Singleton instance() { if ( s is null ) s = new Singleton( 0 ) ; return * s ; } int val = 0 ; } [/code] This compiles, but when I use it: [code] auto s = Singleton.instance ; writeln( s.val ) ; Singleton.instance.val = 2 ; writeln( s.val ) ; [/code] I get: 0 0 Where is my mistake ? Cheers, PP !Even if Singleton.instance returns by ref, s object is still stack-allocated struct, which is not affected by further modification of private pointer. import core.stdc.stdio : printf; struct Singleton { private : this( int a = 0 ) {} ; static Singleton * s ; public : disable this() ; static ref Singleton instance() { if ( s is null ) s = new Singleton(0) ; return * s ; } int val = 0 ; } void main() { auto s = Singleton.instance ; printf( "%d\n", s.val ) ; //0 Singleton.instance.val = 2 ; printf( "%d\n", s.val ) ; // also 0 printf( "%d\n", Singleton.instance.val); // is 2 as expected }
Jan 24 2013
On 2013-01-24 15:43, Maxim Fomin wrote:Even if Singleton.instance returns by ref, s object is still stack-allocated struct, which is not affected by further modification of private pointer.The struct is allocated using "new". -- /Jacob Carlborg
Jan 24 2013
On Thursday, 24 January 2013 at 15:05:15 UTC, Jacob Carlborg wrote:On 2013-01-24 15:43, Maxim Fomin wrote:This is about "auto s = " in main, not about "new" in method. Type of s is Singleton, not Singleton* or "ref Singleton". Singleton s = Singleton.instance; // is compiled when Singleton* s = Singleton.instance; // is not - Error: cannot implicitly convert // expression (instance()) of type Singleton to Singleton*Even if Singleton.instance returns by ref, s object is still stack-allocated struct, which is not affected by further modification of private pointer.The struct is allocated using "new".
Jan 24 2013
Got it, thanks, I changed the instance method to: [code] static Singleton * instance() { if ( s is null ) s = new Singleton( 0 ) ; return s ; } [\code] and everything works as expected. Cheers, PP !
Jan 24 2013
On Thursday, 24 January 2013 at 15:50:34 UTC, ParticlePeter wrote:Got it, thanks, I changed the instance method to: [code] static Singleton * instance() { if ( s is null ) s = new Singleton( 0 ) ; return s ; } [\code] and everything works as expected. Cheers, PP !Yes, but this can be broken by: import core.stdc.stdio : printf; struct Singleton { private : this( int a = 0 ) {} ; static Singleton * s ; public : disable this() ; static Singleton* instance() { if ( s is null ) s = new Singleton(0) ; return s ; } int val = 0 ; } void main() { Singleton s = * Singleton.instance; printf( "%d\n", s.val ) ; // Singleton.instance.val = 2 ; printf( "%d\n", s.val ) ; //0 } Here s is explicitly defined to be a struct object, not pointer (reference), so main.s is independent of further modification of Singleton.instance.
Jan 24 2013
On Thursday, 24 January 2013 at 16:07:36 UTC, Maxim Fomin wrote:Yes, but this can be broken by:void main() { Singleton s = * Singleton.instance; printf( "%d\n", s.val ) ; // Singleton.instance.val = 2 ; printf( "%d\n", s.val ) ; //0 } Here s is explicitly defined to be a struct object, not pointer (reference), so main.s is independent of further modification of Singleton.instance.I'm not sure but this seems like one of the few appropriate places i would just make a normal struct and just use a global variable. True there could 'be' multiple instances of these singletons, but only ever making one ensures it would work right so long as you cannot copy it. Wasn't disabling this(this) and opAssign the way to ensure that didn't happen? Course if you didn't and you relied on the instance one, and you cannot copy then you could only pass by reference or be required to use .instance every time you needed it. Seems a bit excessive. Hmmm. You could separate the data and remove the pointer... then use alias this. [code] struct Singleton { static SingletonData single; alias single this; disable this(this); //disable copy/assignment? Not that it would matter... //copying nothing does nothing, as there's nothing here. private static struct SingletonData { //methods and data here. } } [/code]
Jan 24 2013
On Thursday, 24 January 2013 at 16:17:34 UTC, Era Scarecrow wrote:On Thursday, 24 January 2013 at 16:07:36 UTC, Maxim Fomin wrote:I agree, but disabling ctors makes creating module-level object tricky. Static struct initialization might help.Yes, but this can be broken by:void main() { Singleton s = * Singleton.instance; printf( "%d\n", s.val ) ; // Singleton.instance.val = 2 ; printf( "%d\n", s.val ) ; //0 } Here s is explicitly defined to be a struct object, not pointer (reference), so main.s is independent of further modification of Singleton.instance.I'm not sure but this seems like one of the few appropriate places i would just make a normal struct and just use a global variable. True there could 'be' multiple instances of these singletons, but only ever making one ensures it would work right so long as you cannot copy it. Wasn't disabling this(this) and opAssign the way to ensure that didn't happen? Course if you didn't and you relied on the instance one, and you cannot copy then you could only pass by reference or be required to use .instance every time you needed it. Seems a bit excessive. Hmmm. You could separate the data and remove the pointer... then use alias this. [code] struct Singleton { static SingletonData single; alias single this; disable this(this); //disable copy/assignment? Not that it would matter... //copying nothing does nothing, as there's nothing here. private static struct SingletonData { //methods and data here. } [/code]
Jan 24 2013
On Thursday, 24 January 2013 at 16:49:53 UTC, Maxim Fomin wrote:On Thursday, 24 January 2013 at 16:17:34 UTC, Era Scarecrow wrote:I'll have to agree. But in that case don't disable the default ctor (not that the Singleton has any contents anyways); Actually opAssign/postblit only needs to be disabled inside SingletonData. I'd think that would work. [code] struct Singleton { static SingletonData single; alias single this; private static struct SingletonData { disable void opAssign(); //methods and data here. } } [/code]Hmmm. You could separate the data and remove the pointer... then use alias this. [code] struct Singleton { static SingletonData single; alias single this; disable this(this); //disable copy/assignment? Not that it would matter... //copying nothing does nothing, as there's nothing here. private static struct SingletonData { //methods and data here. } [/code]I agree, but disabling ctors makes creating module-level object tricky. Static struct initialization might help.
Jan 24 2013
Yes, but this can be broken by: import core.stdc.stdio : printf; struct Singleton { private : this( int a = 0 ) {} ; static Singleton * s ; public : disable this() ; static Singleton* instance() { if ( s is null ) s = new Singleton(0) ; return s ; } int val = 0 ; } void main() { Singleton s = * Singleton.instance; printf( "%d\n", s.val ) ; // Singleton.instance.val = 2 ; printf( "%d\n", s.val ) ; //0 } Here s is explicitly defined to be a struct object, not pointer (reference), so main.s is independent of further modification of Singleton.instance.O.k. good to know, I'll try to avoid this. But one thing is still not clear, This method here ( my first approach ) does return a reference to an object on the heap, right ? static ref Singleton instance() { if ( s is null ) s = new Singleton( 0 ) ; return * s ; } so when I use it with: auto another_s = Singleton.instance ; Why is the s inside the struct and another_s not identical ? Afaik that is the purpose of the ref keyword ?
Jan 24 2013
On 01/24/2013 08:52 AM, ParticlePeter wrote:This method here ( my first approach ) does return a reference to an object on the heap, right ?Yes, but the caller does not get a reference.static ref Singleton instance() { if ( s is null ) s = new Singleton( 0 ) ; return * s ; } so when I use it with: auto another_s = Singleton.instance ; Why is the s inside the struct and another_s not identical ? Afaik that is the purpose of the ref keyword ?When you print the type of another_s you will see that it is not a ref, because unlike C++, D does not have local ref variables; it has pointers for that purpose. import std.stdio; ref int foo() { return *new int; } void main() { auto i = foo(); writeln(typeid(i)); } Prints 'int', not 'ref int'. So, i is a copy of the dynamically created int. Ali
Jan 24 2013
On Thursday, 24 January 2013 at 17:00:44 UTC, Ali Çehreli wrote:On 01/24/2013 08:52 AM, ParticlePeter wrote:Actually the caller gets the reference (which is a pointer from low-level POV), but allocates on stack struct object, and then does copy from returned reference to that stack object.This method here ( my first approach ) does return areference to anobject on the heap, right ?Yes, but the caller does not get a reference.Yes, that the point - D does not have references like C++. And I should thought about C++ influence on understanding D :)static ref Singleton instance() { if ( s is null ) s = new Singleton( 0 ) ; return * s ; } so when I use it with: auto another_s = Singleton.instance ; Why is the s inside the struct and another_s not identical ? Afaik that is the purpose of the ref keyword ?When you print the type of another_s you will see that it is not a ref, because unlike C++, D does not have local ref variables; it has pointers for that purpose.import std.stdio; ref int foo() { return *new int; } void main() { auto i = foo(); writeln(typeid(i)); } Prints 'int', not 'ref int'. So, i is a copy of the dynamically created int. Ali
Jan 24 2013
On Thursday, 24 January 2013 at 17:00:44 UTC, Ali Çehreli wrote:On 01/24/2013 08:52 AM, ParticlePeter wrote:Thanks, I re-read the purpose of ref type function() in the D programming language, and the sole purpose is that such a function call can be directly a parameter to another function expecting a ref ? As: ref int foo() { return some class member ; } void bar( ref int data ) { do something with data ; } This means, it is never ever possible to initialize any variable with a reference some class/struct member data ? Unless I return the address of the member data ?This method here ( my first approach ) does return areference to anobject on the heap, right ?Yes, but the caller does not get a reference.static ref Singleton instance() { if ( s is null ) s = new Singleton( 0 ) ; return * s ; } so when I use it with: auto another_s = Singleton.instance ; Why is the s inside the struct and another_s not identical ? Afaik that is the purpose of the ref keyword ?When you print the type of another_s you will see that it is not a ref, because unlike C++, D does not have local ref variables; it has pointers for that purpose. import std.stdio; ref int foo() { return *new int; } void main() { auto i = foo(); writeln(typeid(i)); } Prints 'int', not 'ref int'. So, i is a copy of the dynamically created int. Ali
Jan 24 2013
On 01/24/2013 09:26 AM, ParticlePeter wrote:Thanks, I re-read the purpose of ref type function() in the D programming language, and the sole purpose is that such a function call can be directly a parameter to another function expecting a ref ?As Maxim Fomin noted, I didn't word it correctly: The caller does get a reference to the returned object. So, the sole purpose is not to pass a variable to a ref-taking function.As: ref int foo() { return some class member ; } void bar( ref int data ) { do something with data ; } This means, it is never ever possible to initialize any variable with a reference some class/struct member data ? Unless I return the address of the member data ?Not true. There are no local ref variables nor ref member variables in D. All you need to do is to use pointers instead: ref int foo() { return *new int; } struct S { int i; int * j; this(int i) { this.i = i; this.j = &foo(); // member pointer } } void main() { int* i = &foo(); // local pointer } No, the pointer syntax is not the cleanest. :) Ali
Jan 24 2013
On Thursday, 24 January 2013 at 17:35:58 UTC, Ali Çehreli wrote:On 01/24/2013 09:26 AM, ParticlePeter wrote:This is what I meant :-) I can't return a reference ( with reference I don't mean reference type, but semantically a reference ) to a class member, but I can return the address of this member, which, to my understanding is an implicit pointer. struct Foo { int val = 3 ; auto getValPtr() { return & val ; } } Foo foo ; writeln( foo.val ) ; // = 3 auto valPtr = foo.getValPtr() ; * valPtr = 7 ; writeln( foo.val ) ; // = 7Thanks, I re-read the purpose of ref type function() in the D programming language, and the sole purpose is that such afunction callcan be directly a parameter to another function expecting aref ? As Maxim Fomin noted, I didn't word it correctly: The caller does get a reference to the returned object. So, the sole purpose is not to pass a variable to a ref-taking function.As: ref int foo() { return some class member ; } void bar( ref int data ) { do something with data ; } This means, it is never ever possible to initialize anyvariable with areference some class/struct member data ? Unless I return theaddress ofthe member data ?Not true. There are no local ref variables nor ref member variables in D. All you need to do is to use pointers instead: ref int foo() { return *new int; } struct S { int i; int * j; this(int i) { this.i = i; this.j = &foo(); // member pointer } } void main() { int* i = &foo(); // local pointer } No, the pointer syntax is not the cleanest. :) Ali
Jan 24 2013
On 01/24/13 17:52, ParticlePeter wrote:There currently are no reference variables in D [1]; the only way to get a reference to something is via function arguments (including implicit method ones) and function returns. So assigning a ref-return means a copy. You can workaround it like this: struct Singleton { private: this( int a = 0 ) {} ; static Singleton* s ; public: disable this(); disable this(this); static instance() property { static struct Ref(T) { T* obj; ref g() property { return *obj; } alias obj this; disable this(this); } if ( s is null ) s = new Singleton( 0 ) ; return Ref!(typeof(this))(s) ; } int val = 0 ; } though, that's not how I'd do it. artur [1] Classes don't count; they are a reference /types/.Yes, but this can be broken by: import core.stdc.stdio : printf; struct Singleton { private : this( int a = 0 ) {} ; static Singleton * s ; public : disable this() ; static Singleton* instance() { if ( s is null ) s = new Singleton(0) ; return s ; } int val = 0 ; } void main() { Singleton s = * Singleton.instance; printf( "%d\n", s.val ) ; // Singleton.instance.val = 2 ; printf( "%d\n", s.val ) ; //0 } Here s is explicitly defined to be a struct object, not pointer (reference), so main.s is independent of further modification of Singleton.instance.O.k. good to know, I'll try to avoid this. But one thing is still not clear, This method here ( my first approach ) does return a reference to an object on the heap, right ? static ref Singleton instance() { if ( s is null ) s = new Singleton( 0 ) ; return * s ; } so when I use it with: auto another_s = Singleton.instance ; Why is the s inside the struct and another_s not identical ? Afaik that is the purpose of the ref keyword ?
Jan 24 2013
On Thursday, 24 January 2013 at 17:21:38 UTC, Artur Skawina wrote:On 01/24/13 17:52, ParticlePeter wrote:Well ... I think I as well would not wanna do it like this, thanks :-) I'm fine with returning and using a pointer, fortunately there is no difference in syntax as in c, so it doesn't matter.There currently are no reference variables in D [1]; the only way to get a reference to something is via function arguments (including implicit method ones) and function returns. So assigning a ref-return means a copy. You can workaround it like this: struct Singleton { private: this( int a = 0 ) {} ; static Singleton* s ; public: disable this(); disable this(this); static instance() property { static struct Ref(T) { T* obj; ref g() property { return *obj; } alias obj this; disable this(this); } if ( s is null ) s = new Singleton( 0 ) ; return Ref!(typeof(this))(s) ; } int val = 0 ; } though, that's not how I'd do it. artur [1] Classes don't count; they are a reference /types/.Yes, but this can be broken by: import core.stdc.stdio : printf; struct Singleton { private : this( int a = 0 ) {} ; static Singleton * s ; public : disable this() ; static Singleton* instance() { if ( s is null ) s = new Singleton(0) ; return s ; } int val = 0 ; } void main() { Singleton s = * Singleton.instance; printf( "%d\n", s.val ) ; // Singleton.instance.val = 2 ; printf( "%d\n", s.val ) ; //0 } Here s is explicitly defined to be a struct object, not pointer (reference), so main.s is independent of further modification of Singleton.instance.O.k. good to know, I'll try to avoid this. But one thing is still not clear, This method here ( my first approach ) does return a reference to an object on the heap, right ? static ref Singleton instance() { if ( s is null ) s = new Singleton( 0 ) ; return * s ; } so when I use it with: auto another_s = Singleton.instance ; Why is the s inside the struct and another_s not identical ? Afaik that is the purpose of the ref keyword ?
Jan 24 2013
On 01/24/2013 09:35 AM, ParticlePeter wrote:I'm fine with returning and using a pointer, fortunately there is no difference in syntax as in c, so it doesn't matter.With the exception that the -> operator is replaced by the dot operator in D: MyStruct * p = /* ... */; // Dot, not -> p.foo(); p.i = 42; Ali
Jan 24 2013
On 01/24/13 18:35, ParticlePeter wrote:On Thursday, 24 January 2013 at 17:21:38 UTC, Artur Skawina wrote:On 01/24/13 17:52, ParticlePeter wrote:Why is the s inside the struct and another_s not identical ? Afaik that is the purpose of the ref keyword ?There currently are no reference variables in D [1]; the only way to get a reference to something is via function arguments (including implicit method ones) and function returns. So assigning a ref-return means a copy. You can workaround it like this: struct Singleton { private: this( int a = 0 ) {} ; static Singleton* s ; public: disable this(); disable this(this); static instance() property { static struct Ref(T) { T* obj; ref g() property { return *obj; } alias g this; disable this(this); } if ( s is null ) s = new Singleton( 0 ) ; return Ref!(typeof(this))(s) ; } int val = 0 ; }Well ... I think I as well would not wanna do it like this, thanks :-) I'm fine with returning and using a pointer, fortunately there is no difference in syntax as in c, so it doesn't matter.Careful, at some point you'll end up doing s[1] etc, and /then/ it matters. The Ref struct is actually the way to deal with "ref" types in D; what I meant by 'that's not how I'd do it' is that it might be better to use a global (well, thread-local module-field in D) etc. artur
Jan 24 2013
On 01/24/13 18:14, Artur Skawina wrote:struct Singleton { private: this( int a = 0 ) {} ; static Singleton* s ; public: disable this(); disable this(this); static instance() property { static struct Ref(T) { T* obj; ref g() property { return *obj; } alias obj this; disable this(this); } if ( s is null ) s = new Singleton( 0 ) ; return Ref!(typeof(this))(s) ; } int val = 0 ; }Grr. What I meant to write was of course: static struct Ref(T) { T* obj; ref g() property { return *obj; } alias g this; disable this(this); } Sorry, artur
Jan 24 2013
Even if Singleton.instance returns by ref, s object is still stack-allocated struct, which is not affected by further modification of private pointer.But where and when is ( a second ? ) Singleton created or duplicated ? The only ctor is in the static instance ( it is called only once according to my debugger ) and allocates a Singleton instance on the Heap ( as far as I understand "new Struct" ). The return statement does return a reference ( to a pointer, even that shouldn't be necessary ) so I would expect ... well a reference and not a copy. So where does the second object come from ?
Jan 24 2013