Defining a custom *constructor* (not initializer!)

Steven Schveighoffer schveiguy at yahoo.com
Mon May 7 14:07:14 PDT 2012


On Mon, 07 May 2012 16:09:06 -0400, Mehrdad <wfunction at 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.

> Regarding #2, in case it doesn't make sense why:
> 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


More information about the Digitalmars-d mailing list