www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Defining a custom *constructor* (not initializer!)

reply "Mehrdad" <wfunction hotmail.com> writes:
Is this possible in D2?

i.e. I'm wondering if there is a way to do the object
construction yourself, which would allow you to call the object's
"constructor" (initializer) manually, and just return a pointer
to the new object.

Something along the lines of:

	class Window
	{
		static Window opConstruct(void* ptr)
		{
			// Assume ptr is already correctly sized and filled
			Window result = cast(Window)ptr;
			result.__ctor();
			return return result;
		}
	}

It seems like overloading new() *almost* does this, but not
quite: It only lets you allocate the memory, not call the
constructor yourself.

This would be useful, because some objects can have external
constructors (notably when interfacing with C/C++, such as when
using CreateWindow() in Windows), and you *cannot* call these
constructors inside the object's "constructor" (initializer) due
to re-entrancy issues.
May 06 2012
next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
Oh, and add "custom destructors" to that question as well: static 
methods that call ~this() manually on the object.
May 06 2012
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-05-06 21:55, Mehrdad wrote:
 Is this possible in D2?

 i.e. I'm wondering if there is a way to do the object
 construction yourself, which would allow you to call the object's
 "constructor" (initializer) manually, and just return a pointer
 to the new object.

 Something along the lines of:

 class Window
 {
 static Window opConstruct(void* ptr)
 {
 // Assume ptr is already correctly sized and filled
 Window result = cast(Window)ptr;
 result.__ctor();
 return return result;
 }
 }

 It seems like overloading new() *almost* does this, but not
 quite: It only lets you allocate the memory, not call the
 constructor yourself.

 This would be useful, because some objects can have external
 constructors (notably when interfacing with C/C++, such as when
 using CreateWindow() in Windows), and you *cannot* call these
 constructors inside the object's "constructor" (initializer) due
 to re-entrancy issues.
You can have a look at my Orange library: https://github.com/jacob-carlborg/orange/blob/master/orange/util/Reflection.d#L460 It's basically what TypeInfo_Class.create does but it doesn't call the constructor and works for LDC as well. https://github.com/D-Programming-Language/druntime/blob/master/src/object_.d#L878 -- /Jacob Carlborg
May 06 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 7 May 2012 at 06:51:43 UTC, Jacob Carlborg wrote:
 You can have a look at my Orange library:

 https://github.com/jacob-carlborg/orange/blob/master/orange/util/Reflection.d#L460

 It's basically what TypeInfo_Class.create does but it doesn't 
 call the constructor and works for LDC as well.

 https://github.com/D-Programming-Language/druntime/blob/master/src/object_.d#L878
Thanks for the reply. Is this something that actually modifies the 'new' operator, or is it just a separate factory function that my code would need to switch to using?
May 07 2012
next sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
On Monday, 7 May 2012 at 07:28:18 UTC, Mehrdad wrote:
 Is this something that actually modifies the 'new' operator, or 
 is it just a separate factory function that my code would need 
 to switch to using?
Doing it without a separate factory function (and maybe disabling new along with it by protecting the constructor) is not possible in D. However, I don't quite see what it would gain you in the first place – besides potentially screwing up the semantics users expect from new… David
May 07 2012
next sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 7 May 2012 at 09:18:11 UTC, David Nadlinger wrote:
 On Monday, 7 May 2012 at 07:28:18 UTC, Mehrdad wrote:
 Is this something that actually modifies the 'new' operator,  
 or is it just a separate factory function that my code would  
 need to switch to using?
Doing it without a separate factory function (and maybe disabling new along with it by protecting the constructor) is not possible in D. However, I don't quite see what it would gain you in the first place – besides potentially screwing up the semantics users expect from new…
What is your objective? What are you trying to achieve? I keep getting the impression of you using a object factory and a static function to create your objects, which would give you more optional behavior but not using new directly. class X { static X makeX() { X x; //make X or OOP descendant and return by whatever rules you need return x; } } Too much control is worse than not enough control. When I was testing out C++11 and getting my hands dirty, bugs were easily introduced where if you had to control certain gritty details, all details had to be controlled for it to work. If you don't have to control it, go around it to a simpler although slightly longer solution.
May 07 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 7 May 2012 at 10:15:56 UTC, Era Scarecrow wrote:
 
  What is your objective? What are you trying to achieve?
Did you read my first post? I already explained what this would be used for. Sure, you can do it with factories, but you can't factory-ize "delete", can you?
May 07 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 07 May 2012 11:57:22 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Monday, 7 May 2012 at 10:15:56 UTC, Era Scarecrow wrote:
   What is your objective? What are you trying to achieve?
Did you read my first post? I already explained what this would be used for. Sure, you can do it with factories, but you can't factory-ize "delete", can you?
Not really, but then again, if you are not placing the class into the GC heap, who cares? You have to manually delete anyways, just use your specialized 'delete' function instead of delete. -Steve
May 07 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 7 May 2012 at 17:04:08 UTC, Steven Schveighoffer wrote:
 Not really, but then again, if you are not placing the class 
 into the GC heap, who cares?  You have to manually delete 
 anyways, just use your specialized 'delete' function instead of 
 delete.

 -Steve
No, I *am* placing it on the heap. I'm just asking if I can call the constructor manually, because (like I wrote in my first post...) sometimes the C code you're interoperating with takes control away from you, and just calls a callback on your behalf when constructing the object. (Yes, I realize there are different solutions to this problem. They're just not as elegant.)
May 07 2012
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
Oh, and ditto with the destructor: I need to be able to call the 
destructor manually, because the C does that inside a callback on 
my behalf.

On Monday, 7 May 2012 at 19:08:18 UTC, Mehrdad wrote:
 No, I *am* placing it on the heap.

 I'm just asking if I can call the constructor manually, because
 (like I wrote in my first post...) sometimes the C code you're
 interoperating with takes control away from you, and just calls 
 a
 callback on your behalf when constructing the object.

 (Yes, I realize there are different solutions to this problem.
 They're just not as elegant.)
May 07 2012
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 07 May 2012 15:09:34 -0400, Mehrdad <wfunction hotmail.com> wrote:

 Oh, and ditto with the destructor: I need to be able to call the  
 destructor manually, because the C does that inside a callback on my  
 behalf.
You definitely can do this. I think it's just __dtor. But I'm not sure if that calls the whole chain. rt_finalize, the function that actually calls the dtors calls each dtor in the chain individually. You can see how it works here: https://github.com/D-Programming-Language/druntime/blob/master/src/rt/lifetime.d#L1161 However, if C is calling your dtor, I'd highly recommend *not* using GC memory for your class data, you can std.conv.emplace it in C-malloced memory. If it has any references to GC data, use GC.addRoot to make sure that data isn't accidentally collected, and use GC.removeRoot before destruction. -Steve
May 07 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-05-07 21:09, Mehrdad wrote:
 Oh, and ditto with the destructor: I need to be able to call the
 destructor manually, because the C does that inside a callback on my
 behalf.
About the destructor, have a look at how "clear" is implemented, it's supposed to replace "delete". Don't remember where it's defined. -- /Jacob Carlborg
May 07 2012
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 07 May 2012 15:08:16 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Monday, 7 May 2012 at 17:04:08 UTC, Steven Schveighoffer wrote:
 Not really, but then again, if you are not placing the class into the  
 GC heap, who cares?  You have to manually delete anyways, just use your  
 specialized 'delete' function instead of delete.

 -Steve
No, I *am* placing it on the heap.
You hadn't made that clear. In your first post, I was assuming your ptr came from some non-GC allocated space, which is why you wanted the ability to intercept it.
 I'm just asking if I can call the constructor manually, because
 (like I wrote in my first post...) sometimes the C code you're
 interoperating with takes control away from you, and just calls a
 callback on your behalf when constructing the object.
I wasn't sure, but I just tried it out: import std.stdio; extern(C) void *_d_newclass(TypeInfo t); // this is defined in rt/lifetime.d I cheated and used this, because I didn't want to have to type everything that was in it :) class C { int x; this(int x){this.x = x;} } void main() { C c = cast(C)_d_newclass(typeid(C)); c.__ctor(1); writeln(c.x); // outputs 1 } Seems to work -Steve
May 07 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 7 May 2012 at 19:39:04 UTC, Steven Schveighoffer wrote:
 I'm just asking if I can call the constructor manually, because
 (like I wrote in my first post...) sometimes the C code you're
 interoperating with takes control away from you, and just 
 calls a
 callback on your behalf when constructing the object.
I wasn't sure, but I just tried it out: import std.stdio; extern(C) void *_d_newclass(TypeInfo t); class C { int x; this(int x){this.x = x;} } void main() { C c = cast(C)_d_newclass(typeid(C)); c.__ctor(1); writeln(c.x); // outputs 1 } Seems to work -Steve
Nonono :( you still missed what I was saying. Unless you're suggesting I replace _d_newclass, but that isn't type-specific (and I certainly don't want to replace it globally). Here's another attempt at the explanation: I definitely CAN make a helper method to do this for me. It's the whole factory pattern, etc. The problems are that: (1) The user wouldn't be able to say "new Window()" anymore (I already explained why) (2) The object couldn't be garbage collected. It's because the C code takes control *AWAY* from you when you tell it to destroy the object. In my case, DestroyWindow(HWND) calls WndProc(WM_DESTROY,..), which is a member function. I CANNOT call DestroyWindow() in the finalizer, because then WndProc would be called on a *derived* class during cleanup. (It's the *same* issue as with the constructor.) So I'd have to do this manually, which defeats the whole point of making the object garbage-collectible in the first place. What I'm *want* to be able to do is, basically, to specify that I have a static method that will take care of finalizing an object. (Something like: void finalize(Window o)) Then, when the object is being finalized, the garbage collector would NOT call the object's finalizer directly. Instead, it would call my STATIC method to do the rest of the cleanup. The STATIC destruction method would call DestroyWindow() on the handle, and DestroyWindow() would send the notification to the window through a modified WndProc() (which I can always redirect, to make it NOT be a member function during the following phase). It would pass in a context parameter -- which would probably be the Window object itself -- to my (redirected) WndProc. The WndProc() would THEN call the Window's finalizer manually (and tell the GC that the object is done being finalized, so it can be collected). I can't think of any "nice" way around this. Either the HWND would have to be managed manually (in which case, that defeats the purpose of using the GC to ensure its destruction along with the object), or I would need an extra indirection in Window (which REALLY overcomplicates the design, and introduces lots of inheritance/template usage issues). The thing is, I think this doesn't need any compiler support either -- just a change in druntime. (I could be wrong though, since it might involve modifying TypeInfo_Class, I'm not sure.) Do you (or others) reckon a pull request to modify _d_newclass and _d_delclass so that they would call a custom static "constructor" and "destructor" for a class (if it specifies this should be the case) might be accepted? If there's the possibility then I might try hacking around with it... I can already see there being issues with inheritance, but I think it would be fixable in some cases, and disallowable in others. (Would obviously need to try it and see though.)
May 07 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 07 May 2012 16:09:06 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Monday, 7 May 2012 at 19:39:04 UTC, Steven Schveighoffer wrote:
 I'm just asking if I can call the constructor manually, because
 (like I wrote in my first post...) sometimes the C code you're
 interoperating with takes control away from you, and just calls a
 callback on your behalf when constructing the object.
I wasn't sure, but I just tried it out: import std.stdio; extern(C) void *_d_newclass(TypeInfo t); class C { int x; this(int x){this.x = x;} } void main() { C c = cast(C)_d_newclass(typeid(C)); c.__ctor(1); writeln(c.x); // outputs 1 } Seems to work -Steve
Nonono :( you still missed what I was saying. Unless you're suggesting I replace _d_newclass, but that isn't type-specific (and I certainly don't want to replace it globally).
All _d_newclass does is allocate memory for the object and initialize it to it's initial state (i.e. if an int member is initialized to 5, it does this). It does not call the constructor. So no, I was assuming you'd either re-use it, or implement some other allocation means.
 Here's another attempt at the explanation:

 I definitely CAN make a helper method to do this for me. It's the whole  
 factory pattern, etc.

 The problems are that:
 (1) The user wouldn't be able to say "new Window()" anymore (I already  
 explained why)
Right. new === allocate memory on the GC heap (via _d_newclass) and call the constructor. If you don't want that you cannot use new.
 (2) The object couldn't be garbage collected.
Then you definitely don't want GC allocated memory.

 It's because the C code takes control *AWAY* from you when you tell it  
 to destroy the object.
 In my case, DestroyWindow(HWND) calls WndProc(WM_DESTROY,..), which is a  
 member function.
So it should not call GC.malloc to create the memory, use C's malloc, and GC.addRoot.
 I CANNOT call DestroyWindow() in the finalizer, because then WndProc  
 would be called on a *derived* class during cleanup. (It's the *same*  
 issue as with the constructor.) So I'd have to do this manually, which  
 defeats the whole point of making the object garbage-collectible in the  
 first place.


 What I'm  *want* to be able to do is, basically, to specify that I have  
 a static method that will take care of finalizing an object. (Something  
 like: void finalize(Window o))
What I think you want is both an allocator/initializer and a destructor. Kind of like malloc and free. The two are going to be tied together, so you should always have to call the correct destructor for an object allocated with the initializer.
 Then, when the object is being finalized, the garbage collector would  
 NOT call the object's finalizer directly. Instead, it would call my  
 STATIC method to do the rest of the cleanup.

 The STATIC destruction method would call DestroyWindow() on the handle,  
 and DestroyWindow() would send the notification to the window through a  
 modified WndProc() (which I can always redirect, to make it NOT be a  
 member function during the following phase).

 It would pass in a context parameter -- which would probably be the  
 Window object itself -- to my (redirected) WndProc.
 The WndProc() would THEN call the Window's finalizer manually (and tell  
 the GC that the object is done being finalized, so it can be collected).
I think avoiding the GC completely is a much better idea. All you need to be concerned about is references from your object into the GC heap (i.e. use addRoot/removeRoot).
 I can't think of any "nice" way around this. Either the HWND would have  
 to be managed manually (in which case, that defeats the purpose of using  
 the GC to ensure its destruction along with the object), or I would need  
 an extra indirection in Window (which REALLY overcomplicates the design,  
 and introduces lots of inheritance/template usage issues).
I guess I don't really understand that. Who is responsible for cleaning up your class instance? The way I was understanding your description, I thought it was the C window runtime calling a callback you provide to it. Why do you need to have the GC clean it up?
 Do you (or others) reckon a pull request to modify _d_newclass and  
 _d_delclass so that they would call a custom static "constructor" and  
 "destructor" for a class (if it specifies this should be the case) might  
 be accepted?
_d_newclass does *not* call ctors, the compiler does that when you say "new" Otherwise, _d_newclass it would have to handle passing through all the parameters to the ctor. It does roughly what I showed you in my quick example. -Steve
May 07 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 7 May 2012 at 21:07:15 UTC, Steven Schveighoffer wrote:
 I guess I don't really understand that.  Who is responsible for 
 cleaning up your class instance?  The way I was understanding 
 your description, I thought it was the C window runtime calling 
 a callback you provide to it.  Why do you need to have the GC 
 clean it up?
Ah, I see why that's confusing. Here's a (hopefully better) explanation: Just as with any other object that represents an outside resource (e.g. a File/Stream/whatever), the lifetime of the unmanaged object should always follow the lifetime of the managed object. In other words, this means that the creation of a Window object MUST be associated with the system call CreateWindow() (which in turns calls the window dispatcher function, WndProc, with the message WM_CREATE). And, more importantly, this means that if the GC collects the Window object, then DestroyWindow() MUST be called on the kernel object, so that the window handle doesn't get leaked. Just as with any other resource. The trouble is that, as-is, this behavior is NOT implementable with a simple Window class whose constructor calls CreateWindow() and whose destructor calls DestroyWindow(). Why? Because if you were to do that in the constructor or destructor, the system would call back your WndProc() function, which is a *virtual* function meant to be overridden in the derived classes (so that they can handle events, such as the creation/destruction of the window, or the calculation of the window size, etc. properly). That would mean your WndProc() in the derived instance would be called *before* the constructor of the derived instance is called, which is obviously not what you want. Ditto with the destructor -- if you were to call DestroyWindow() in the ~Window(), then it would call back WndProc with the message WM_DESTROY in the derived class. The only solution I see is to somehow call DestroyWindow() *BEFORE* you call the destructor, and call the destructor manually when the WM_DESTROY message is received. Ditto with the constructor: you need to somehow call CreateWindow() *BEFORE* you call the constructor, so that when you receive the WM_CREATE message, you can call the constructor manually. Only by hijacking the construction and destruction call can you guarantee that the construction/destruction happens in an orderly fashion, i.e. that the kernel object lifetime tracks the user object lifetime properly. Otherwise you either miss getting some notifications at critical points (which results in incorrect code, which some people may or may not care about), or you risk getting a handle leak (also obviously bad). Or you risk making the design pattern pretty horrific, kind of they both have creation parameters, and they both register themselves ("park" themselves) globally on a static/shared field, and run into all sorts of ugly issues that you shouldn't need to run into. (If you look at the code and understand what they're doing, you'll see what I mean when I say it's ugly...) Summary: Yes, I need the GC so I can manage the HWND lifetime properly, i.e. so it tracks the lifetime of the Window object (otherwise you can easily leak a handle). But in order to do this, I also need to be able to call the constructor/destructor manually, because the C code does this through a callback, which isn't possible when your object is being GC'd, due to virtual method re-entrancy issues with finalization. Does that make sense? Is any part of it still unclear?
May 07 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 07 May 2012 19:00:22 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Monday, 7 May 2012 at 21:07:15 UTC, Steven Schveighoffer wrote:
 I guess I don't really understand that.  Who is responsible for  
 cleaning up your class instance?  The way I was understanding your  
 description, I thought it was the C window runtime calling a callback  
 you provide to it.  Why do you need to have the GC clean it up?
Ah, I see why that's confusing. Here's a (hopefully better) explanation: Just as with any other object that represents an outside resource (e.g. a File/Stream/whatever), the lifetime of the unmanaged object should always follow the lifetime of the managed object. In other words, this means that the creation of a Window object MUST be associated with the system call CreateWindow() (which in turns calls the window dispatcher function, WndProc, with the message WM_CREATE). And, more importantly, this means that if the GC collects the Window object, then DestroyWindow() MUST be called on the kernel object, so that the window handle doesn't get leaked. Just as with any other resource. The trouble is that, as-is, this behavior is NOT implementable with a simple Window class whose constructor calls CreateWindow() and whose destructor calls DestroyWindow(). Why? Because if you were to do that in the constructor or destructor, the system would call back your WndProc() function, which is a *virtual* function meant to be overridden in the derived classes (so that they can handle events, such as the creation/destruction of the window, or the calculation of the window size, etc. properly). That would mean your WndProc() in the derived instance would be called *before* the constructor of the derived instance is called, which is obviously not what you want.
OK, I understand what you are saying now. What about using NVI? class Window { protected void processMessage_impl(int message) // virtual call {} final public void processMessage(int message) { if(message == WM_CREATE) { // handle specially } else if(message == WM_DELETE) { // handle specially } else { processMessage_impl(int message); } } private HWND window; this() { window = CreateWindow(&processMessage); // or whatever mechanism, you get the idea } ~this() { DestroyWindow(window); } } -Steve
May 11 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
 OK, I understand what you are saying now.

 What about using NVI?

 class Window
 {
   protected void processMessage_impl(int message) // virtual 
 call
   {}
   final public void processMessage(int message)
   {
     if(message == WM_CREATE)
     {
        // handle specially
     }
     else if(message == WM_DELETE)
     {
        // handle specially
     }
     else
     {
         processMessage_impl(int message);
     }
   }
   private HWND window;
   this()
   {
     window = CreateWindow(&processMessage); // or whatever 
 mechanism, you get the idea
   }
   ~this()
   {
     DestroyWindow(window);
   }
 }

 -Steve
The trouble is that if you "handle these specially", then your subclasses won't.... But your subclasses MUST still be able to handle these messages, because they might need to do something special when the messages are sent. (For example, you might need to calculate the size of the window when WM_CREATE or WM_NCCREATE is sent. Or something else... there are a ton of situations that can happen -- such as MDI window creation, etc. -- that don't happen too often, but happen often enough that you simply can't assume you can get by without allowing them to handle the messages.)
May 11 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 11 May 2012 09:33:54 -0400, Mehrdad <wfunction hotmail.com> wrote:

 OK, I understand what you are saying now.

 What about using NVI?

 class Window
 {
   protected void processMessage_impl(int message) // virtual call
   {}
   final public void processMessage(int message)
   {
     if(message == WM_CREATE)
     {
        // handle specially
     }
     else if(message == WM_DELETE)
     {
        // handle specially
     }
     else
     {
         processMessage_impl(int message);
     }
   }
   private HWND window;
   this()
   {
     window = CreateWindow(&processMessage); // or whatever mechanism,  
 you get the idea
   }
   ~this()
   {
     DestroyWindow(window);
   }
 }

 -Steve
The trouble is that if you "handle these specially", then your subclasses won't.... But your subclasses MUST still be able to handle these messages, because they might need to do something special when the messages are sent. (For example, you might need to calculate the size of the window when WM_CREATE or WM_NCCREATE is sent.
I'm probably not getting the entire picture here, but I assume from your description that CreateWindow directly calls your WndProc. If that is the case, isn't it guaranteed that after the base ctor runs the class has received the WM_CREATE message? I mean, the only issue happens when you are not quite through the ctor chain, no?
 Or something else... there are a ton of situations that can happen --  
 such as MDI window creation, etc. -- that don't happen too often, but  
 happen often enough that you simply can't assume you can get by without  
 allowing them to handle the messages.)
You can use another mechanism to decide. for instance: class Window private bool inCreateWindow = false; ... final public void processMessage(int message) { if(inCreateWindow && message == WM_CREATE) { // handle specially } ... } this() { inCreateWindow = true; window = CreateWindow(&processMessage); inCreateWindow = false; // all WM_CREATE messages will now go through normal mechanism. } } -Steve
May 11 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
 I'm probably not getting the entire picture here, but I assume 
 from your description that CreateWindow directly calls your 
 WndProc.  If that is the case, isn't it guaranteed that after 
 the base ctor runs the class has received the WM_CREATE 
 message?  I mean, the only issue happens when you are not quite 
 through the ctor chain, no?
Right, what I'm saying is that it's the *subclass* who needs the notification more, than anyone else (although, for other reasons, the base class needs it as well). The whole point is to get the messages to the *subclasses* properly...
 Or something else... there are a ton of situations that can 
 happen -- such as MDI window creation, etc. -- that don't 
 happen too often, but happen often enough that you simply 
 can't assume you can get by without allowing them to handle 
 the messages.)
You can use another mechanism to decide. for instance: class Window private bool inCreateWindow = false; ... final public void processMessage(int message) { if(inCreateWindow && message == WM_CREATE) { // handle specially } ... } this() { inCreateWindow = true; window = CreateWindow(&processMessage); inCreateWindow = false; // all WM_CREATE messages will now go through normal mechanism. } } -Steve
May 11 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 11 May 2012 10:04:00 -0400, Mehrdad <wfunction hotmail.com> wrote:

 I'm probably not getting the entire picture here, but I assume from  
 your description that CreateWindow directly calls your WndProc.  If  
 that is the case, isn't it guaranteed that after the base ctor runs the  
 class has received the WM_CREATE message?  I mean, the only issue  
 happens when you are not quite through the ctor chain, no?
Right, what I'm saying is that it's the *subclass* who needs the notification more, than anyone else (although, for other reasons, the base class needs it as well). The whole point is to get the messages to the *subclasses* properly...
Yeah, but given that the subclass is calling the base constructor, and the base constructor does not return until WM_CREATE is received, can't the subclass constructor pretend it received the message? -Steve
May 11 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 11 May 2012 at 14:17:04 UTC, Steven Schveighoffer 
wrote:
 Yeah, but given that the subclass is calling the base 
 constructor, and the base constructor does not return until 
 WM_CREATE is received, can't the subclass constructor pretend 
 it received the message?

 -Steve
"pretend"? No, because the window handle doesn't even EXIST until WM_CREATE passes it to the window instance! (Sorry I guess I didn't mention that, but it was kind of implicit in the fact that messages are passed *before* CreateWindow() returns.) Yes, CreateWindow() also returns a copy of the handle, but stuff happens *before* the handle is returned, and in order for the class to properly handle it, the handle is passed along with WM_CREATE (and, in fact, with another message called WM_NCCREATE, but we can ignore that for now). The subclass has NO access to the window handle whatsoever before the message comes, so no, it can't "pretend" to have received the handle because that wouldn't be of any use.
May 11 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 11 May 2012 at 14:20:47 UTC, Mehrdad wrote:
 On Friday, 11 May 2012 at 14:17:04 UTC, Steven Schveighoffer 
 wrote:
 Yeah, but given that the subclass is calling the base 
 constructor, and the base constructor does not return until 
 WM_CREATE is received, can't the subclass constructor pretend 
 it received the message?

 -Steve
"pretend"? The subclass has NO access to the window handle whatsoever before the message comes, so no, it can't "pretend" to have received the handle because that wouldn't be of any use.
Or did you mean *after* the base class constructor is called? If you meant that: no, that's pretty useless because the whole point of receiving a message is to respond to it appropriately! If you miss the actual notification you can't time-travel back and say, "just kidding, I actually wanted to do X-Y-Z when the message came, so can we redo this whole window creation thing?" :P That's exactly what I was saying when I said that you can't afford to miss a message and hope that you can just change stuff later...
May 11 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 11 May 2012 10:31:26 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Friday, 11 May 2012 at 14:20:47 UTC, Mehrdad wrote:
 On Friday, 11 May 2012 at 14:17:04 UTC, Steven Schveighoffer wrote:
 Yeah, but given that the subclass is calling the base constructor, and  
 the base constructor does not return until WM_CREATE is received,  
 can't the subclass constructor pretend it received the message?

 -Steve
"pretend"? The subclass has NO access to the window handle whatsoever before the message comes, so no, it can't "pretend" to have received the handle because that wouldn't be of any use.
Or did you mean *after* the base class constructor is called? If you meant that: no, that's pretty useless because the whole point of receiving a message is to respond to it appropriately! If you miss the actual notification you can't time-travel back and say, "just kidding, I actually wanted to do X-Y-Z when the message came, so can we redo this whole window creation thing?" :P That's exactly what I was saying when I said that you can't afford to miss a message and hope that you can just change stuff later...
Yes I did mean that. I'm thinking about it, one thing you did not mention, but almost certainly is the case (it usually is with GUI toolkits) is that the WndProc is called in a different thread or context than the constructor. This means, there may be functions that you can call in WndProc that you cannot call in the ctor. So even though CreateWindow returning means WM_CREATE must have been received, the context you need to handle WM_CREATE is gone. Is that true? I'll wait for an answer before thinking more about this. It feels imminently solvable... -Steve
May 11 2012
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 11 May 2012 at 15:23:10 UTC, Steven Schveighoffer 
wrote:
 Yes I did mean that.

 I'm thinking about it, one thing you did not mention, but 
 almost certainly is the case (it usually is with GUI toolkits) 
 is that the WndProc is called in a different thread or context 
 than the constructor.
It's in the same exact thread as the caller of CreateWindow in Win32 (not sure what you mean by "context" here, but AFAIK nothing is changed about the thread... nothing fiber-like or anything like that going on). I'm not familiar with other OSes though.
 This means, there may be functions that you can call in WndProc 
 that you cannot call in the ctor.
 So even though CreateWindow returning means WM_CREATE must have 
 been received, the context you need to handle WM_CREATE is 
 gone.  Is that true?
Again, not sure what you mean by "context", but there is nothing changed about the thread here. You could nest the creation of 10 windows down this chain of WM_CREATE's (in fact, that's one of its purposes) and it's all gonna happen for the same thread, in the same "context" (assuming that's referring to the thread context). Furthermore, the system waits for your response, because if you return -1, the window is not created, and an error is returned to the caller. (Yet another reason why you need to be able to handle the message when it's sent, not a year later.)
 I'll wait for an answer before thinking more about this.  It 
 feels imminently solvable...
Okay. :P Though I've thought about it for a while and I'm getting more and more convinced there isn't a good solution for this without the ability to do custom construction...
May 11 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 11 May 2012 at 15:36:37 UTC, Mehrdad wrote:
 It's in the same exact thread as the caller of CreateWindow in 
 Win32
Minor correction: that's under the assumption that the thread that registered the window class (with RegisterClass()) is the same thread creating the window, which is the case most of the time. But if it's one process instantiating the window of a different process (which happens sometimes), or if it's one thread instantiating the window of a different thread (which happens more rarely), that's obviously not the case...
May 11 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 11 May 2012 at 15:41:02 UTC, Mehrdad wrote:
 On Friday, 11 May 2012 at 15:36:37 UTC, Mehrdad wrote:
 It's in the same exact thread as the caller of CreateWindow in 
 Win32
Minor correction: that's under the assumption that the thread that registered the window class (with RegisterClass()) is the same thread creating the window, which is the case most of the time. But if it's one process instantiating the window of a different process (which happens sometimes), or if it's one thread instantiating the window of a different thread (which happens more rarely), that's obviously not the case...
Never mind, I actually messed up the last part; it's the same thread throughout: http://www.oopweb.com/Assembly/Documents/Win32ASM/Volume/winmsg.htm#windowthread I just got this confused because if you happen to use SendMessage() to send the message, THEN the rule I mentioned applies. But here, the system calls the window procedure directly, and as the link says, only the current ever calls the window procedure.
May 11 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
Since I kinda failed at explaining it, here's a better link, MSDN 
itself:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644950.aspx

Note what it says happens when you call SendMessage():

"If the specified window was created by the calling thread, the 
window procedure is called immediately as a subroutine. If the 
specified window was created by a different thread, the system 
switches to that thread and calls the appropriate window 
procedure. Messages sent between threads are processed only when 
the receiving thread executes message retrieval code. The sending 
thread is blocked until the receiving thread processes the 
message."

So, in other words, the thread of RegisterClass() doesn't have 
much to do with anything so far as the window procedure is 
concerned -- the window procedure is always executed in the same 
thread that created the window. (We're not using SendMessage() 
here, but the rule regarding who can call the window procedure is 
the same.)
May 11 2012
prev sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 11 May 2012 at 15:23:10 UTC, Steven Schveighoffer 
wrote:
 I'll wait for an answer before thinking more about this.  It 
 feels imminently solvable...

 -Steve
Did you come across any ideas? :)
May 31 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 May 2012 03:25:40 -0400, Mehrdad <wfunction hotmail.com> wrote:

 On Friday, 11 May 2012 at 15:23:10 UTC, Steven Schveighoffer wrote:
 I'll wait for an answer before thinking more about this.  It feels  
 imminently solvable...

 -Steve
Did you come across any ideas? :)
Sorry lost track of this. I'll think about it again. -Steve
May 31 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Thursday, 31 May 2012 at 10:58:51 UTC, Steven Schveighoffer 
wrote:
 On Thu, 31 May 2012 03:25:40 -0400, Mehrdad 
 <wfunction hotmail.com> wrote:

 On Friday, 11 May 2012 at 15:23:10 UTC, Steven Schveighoffer 
 wrote:
 I'll wait for an answer before thinking more about this.  It 
 feels imminently solvable...

 -Steve
Did you come across any ideas? :)
Sorry lost track of this. I'll think about it again. -Steve
o lol. ok. Do you think it'd be difficult to add an extra layer of indirection for calling the current "constructors"/finalizers? I feel like, if DMD would just look for a __construct and a __destroy static method instead of directly calling the constructor/finalizer, it'd all work out nicely...
May 31 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
I just added this:
http://d.puremagic.com/issues/show_bug.cgi?id=8177


I don't understand the DMD code well enough to implement this
myself (the identifiers are all Greek to me...), but I honestly
think implementing it should be relatively simple, since the
default implementations are trivial (and I don't think it
requires too much code to be changed in DMD).



If someone could implement it -- or perhaps guide me through
where I should look/how I could implement it myself -- I'd really
appreciate it. :) Thanks!
May 31 2012
prev sibling next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 7 May 2012 at 09:18:11 UTC, David Nadlinger wrote:
 
 Doing it without a separate factory function (and maybe 
 disabling new along with it by protecting the constructor) is 
 not possible in D.
Okay that answers my question then.
 However, I don't quite see what it would gain you in the first 
 place – besides potentially screwing up the semantics users 
 expect from new…
It's a similar thing as when you override new's memory allocation part... yes, it can screw up the semantics, but it's assumed you know what you're doing...
May 07 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-05-07 18:01, Mehrdad wrote:
 On Monday, 7 May 2012 at 09:18:11 UTC, David Nadlinger wrote:
 Doing it without a separate factory function (and maybe disabling new
 along with it by protecting the constructor) is not possible in D.
Okay that answers my question then.
No, have a look at this example: http://pastebin.com/UV5R82dg A bit of a hack. An other option would to use a separate public method that acts as a constructor. -- /Jacob Carlborg
May 07 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-05-07 11:18, David Nadlinger wrote:
 On Monday, 7 May 2012 at 07:28:18 UTC, Mehrdad wrote:
 Is this something that actually modifies the 'new' operator, or is it
 just a separate factory function that my code would need to switch to
 using?
Doing it without a separate factory function (and maybe disabling new along with it by protecting the constructor) is not possible in D. However, I don't quite see what it would gain you in the first place – besides potentially screwing up the semantics users expect from new… David
http://pastebin.com/UV5R82dg A bit of a hack. An other option would to use a separate public method that acts as a constructor. -- /Jacob Carlborg
May 07 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-05-07 09:28, Mehrdad wrote:

 Is this something that actually modifies the 'new' operator, or is it
 just a separate factory function that my code would need to switch to
 using?
This does not modify the new-operator. "_d_newclass" is actually the runtime function that is called by the compiler when it sees "new" in the code. It would be a separate factory function. As far as I know it's not possible to _not_ call the constructor when using new. -- /Jacob Carlborg
May 07 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-05-06 21:55, Mehrdad wrote:
 Is this possible in D2?

 i.e. I'm wondering if there is a way to do the object
 construction yourself, which would allow you to call the object's
 "constructor" (initializer) manually, and just return a pointer
 to the new object.

 Something along the lines of:

 class Window
 {
 static Window opConstruct(void* ptr)
 {
 // Assume ptr is already correctly sized and filled
 Window result = cast(Window)ptr;
 result.__ctor();
 return return result;
 }
 }

 It seems like overloading new() *almost* does this, but not
 quite: It only lets you allocate the memory, not call the
 constructor yourself.

 This would be useful, because some objects can have external
 constructors (notably when interfacing with C/C++, such as when
 using CreateWindow() in Windows), and you *cannot* call these
 constructors inside the object's "constructor" (initializer) due
 to re-entrancy issues.
Don't know if it helps but, have a look the DWT sources: https://github.com/d-widget-toolkit/org.eclipse.swt.win32.win32.x86/tree/master/src/org/eclipse/swt should probably be in the internal folder, widgets/Widget or widgets/Shell. -- /Jacob Carlborg
May 11 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Friday, 11 May 2012 at 22:28:55 UTC, Jacob Carlborg wrote:
 On 2012-05-06 21:55, Mehrdad wrote:
 Is this possible in D2?

 i.e. I'm wondering if there is a way to do the object
 construction yourself, which would allow you to call the 
 object's
 "constructor" (initializer) manually, and just return a pointer
 to the new object.

 Something along the lines of:

 class Window
 {
 static Window opConstruct(void* ptr)
 {
 // Assume ptr is already correctly sized and filled
 Window result = cast(Window)ptr;
 result.__ctor();
 return return result;
 }
 }

 It seems like overloading new() *almost* does this, but not
 quite: It only lets you allocate the memory, not call the
 constructor yourself.

 This would be useful, because some objects can have external
 constructors (notably when interfacing with C/C++, such as when
 using CreateWindow() in Windows), and you *cannot* call these
 constructors inside the object's "constructor" (initializer) 
 due
 to re-entrancy issues.
Don't know if it helps but, have a look the DWT sources: https://github.com/d-widget-toolkit/org.eclipse.swt.win32.win32.x86/tree/master/src/org/eclipse/swt should probably be in the internal folder, widgets/Widget or widgets/Shell.
Thanks for the link. It seems like it's on Control.d... *separate* function, createHandle(), used to create the control. And they simply *don't* tie the destructor to DestroyWindow(); instead, they just assume the user will call dispose(). So in other words, they just ignored the entire problem with the lifetimes, and hoped ("required"?) that the user will call dispose(). Not something I'd want to do, since (even according to .NET's philosophy) a handle leak must NEVER occur, as long as the program has control, even if the user doesn't dispose the object. The closing of the handle can of course be nondeterministic due to the GC, but it must be eventually cleaned up when the object is GC'd. Any ideas if this would be easy/hard to add to DMD/Phobos?
May 11 2012
parent reply "John Chapman" <johnch_atms hotmail.com> writes:

 *separate* function, createHandle(), used to create the control.

 And they simply *don't* tie the destructor to DestroyWindow(); 
 instead, they just assume the user will call dispose().>
 So in other words, they just ignored the entire problem with 
 the lifetimes, and hoped ("required"?) that the user will call 
 dispose().
Actually, in WinForms, closing the application's main Form triggers its Dispose method, which disposes of child Controls too.
May 12 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Saturday, 12 May 2012 at 15:57:37 UTC, John Chapman wrote:

 a *separate* function, createHandle(), used to create the 
 control.

 And they simply *don't* tie the destructor to DestroyWindow(); 
 instead, they just assume the user will call dispose().>
 So in other words, they just ignored the entire problem with 
 the lifetimes, and hoped ("required"?) that the user will call 
 dispose().
Actually, in WinForms, closing the application's main Form triggers its Dispose method, which disposes of child Controls too.
Yes, that's not a WinForms thing -- when you close a window, it's trivial to have DestroyWindow() get called too. The trouble is that you can't rely on this to avoid handle leaks -- for example, message-only windows are invisible, so their handles can get leaked and they can never be closed.
May 12 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-05-12 20:30, Mehrdad wrote:

 Yes, that's not a WinForms thing -- when you close a window, it's
 trivial to have DestroyWindow() get called too.

 The trouble is that you can't rely on this to avoid handle leaks -- for
 example, message-only windows are invisible, so their handles can get
 leaked and they can never be closed.
A DWT Hello World application looks like this: void main () { auto display = new Display; auto shell = new Shell(display); shell.open(); while (!shell.isDisposed) if (!display.readAndDispatch()) display.sleep(); display.dispose(); } You always call "display.dispose" at the end of the main function. Since "dispose" will dispose all of the receiver's children and "display" is the top level widget, everything will be disposed when the application exits. -- /Jacob Carlborg
May 14 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 14 May 2012 at 07:26:27 UTC, Jacob Carlborg wrote:
 You always call "display.dispose" at the end of the main 
 function. Since "dispose" will dispose all of the receiver's 
 children and "display" is the top level widget, everything will 
 be disposed when the application exits.
*sigh* I just spent a few posts explaining why you need to clean things up in the destructor, and then I get a reply telling me to just manage resources manually, screw automatic garbage collection. >_<
May 14 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-05-14 10:10, Mehrdad wrote:
 On Monday, 14 May 2012 at 07:26:27 UTC, Jacob Carlborg wrote:
 You always call "display.dispose" at the end of the main function.
 Since "dispose" will dispose all of the receiver's children and
 "display" is the top level widget, everything will be disposed when
 the application exits.
*sigh* I just spent a few posts explaining why you need to clean things up in the destructor, and then I get a reply telling me to just manage resources manually, screw automatic garbage collection. >_<
No, I'm telling you how SWT/DWT works. How "dispose" works in DWT is _not_ the same as doing managing memory manually. -- /Jacob Carlborg
May 14 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 14 May 2012 at 13:25:11 UTC, Jacob Carlborg wrote:
 No, I'm telling you how SWT/DWT works. How "dispose" works in 
 DWT is _not_ the same as doing managing memory manually.
Memory? The entire issue is about a handle leak, not a memory leak...
May 14 2012