Thread overview
super constructors: I can't take it anymore!
Aug 16, 2006
Serg Kovrov
Aug 16, 2006
Oskar Linde
Aug 16, 2006
Serg Kovrov
Aug 16, 2006
Regan Heath
Aug 16, 2006
Serg Kovrov
Aug 17, 2006
Regan Heath
Aug 16, 2006
Serg Kovrov
Aug 16, 2006
nobody
Aug 16, 2006
Serg Kovrov
August 16, 2006
Hello, everybody,

As subject says I am really on the edge. This implicitly generated parent constructor calls are... Evil.

Here is my near-real class hierarchy:
> class BaseWindow {
>   this() {
>     writefln("register BaseWindowClass");
>     writefln("create");
>   }
> }
> class FrameWindow : BaseWindow {
>   this(char[] caption) {
>     writefln("register FrameWindowClass");
>     writefln("create %s", caption);
>   }
> }
> class MyFrameWindow : FrameWindow {
> 	this(char[] caption) {
> 		super(caption);
> 	}
> }

When I create instance of MyFrameWindow, I've got:
> register BaseWindowClass
> create
> register FrameWindowClass
> create test

I think I understand why, but I'm completely unhappy with it =(

What I want is that the only constructor called were FrameWindow.this(char[]), to have *only* this:
> register FrameWindowClass
> create test


-- 
serg.
August 16, 2006
Serg Kovrov wrote:
> Hello, everybody,
> 
> As subject says I am really on the edge. This implicitly generated parent constructor calls are... Evil.
> 
> Here is my near-real class hierarchy:
>> class BaseWindow {
>>   this() {
>>     writefln("register BaseWindowClass");
>>     writefln("create");
>>   }
>> }
>> class FrameWindow : BaseWindow {
>>   this(char[] caption) {
>>     writefln("register FrameWindowClass");
>>     writefln("create %s", caption);
>>   }
>> }
>> class MyFrameWindow : FrameWindow {
>>     this(char[] caption) {
>>         super(caption);
>>     }
>> }
> 
> When I create instance of MyFrameWindow, I've got:
>> register BaseWindowClass
>> create
>> register FrameWindowClass
>> create test
> 
> I think I understand why, but I'm completely unhappy with it =(
> 
> What I want is that the only constructor called were FrameWindow.this(char[]), to have *only* this:
>> register FrameWindowClass
>> create test

If you want to avoid the default constructor to be called in the base class, I guess you would have to create a overloaded dummy constructor in BaseWindow that you explicitly call in your subclass constructor.

Or, you can reconsider your design. One option is to make a register() method that only the BaseWindow constructor calls. In you child classes, you can overload the register() method anyway you wish.

/Oskar
August 16, 2006
* Oskar Linde:
> Or, you can reconsider your design. One option is to make a register() method that only the BaseWindow constructor calls. In you child classes, you can overload the register() method anyway you wish.

Yes, I thought about reconsider design to workaround this issue, but I can't find clean solution yet.

Let me clear my design. Obvious hierarchy - a base class for common any-window functionality, and subclasses for common window cases (such top frame, button, reac hedit, etc) which may have more narrow but still generic, and finally end-user-classes for particular application.

All windows classes must register (once) os class with its window procedure, and create a os window *when instancing*. That is one thing I do not want to change. e.g, when I do `new Button("push me")` I have button object ready for action. no need/worry to init it, it should be inited in constructor.

Ok, next. I want unique window procedure for each 'generic' window class. eg BaseWindow FrameWindow, Probably I need to explain more, but do not want to bloat this message. In few words it is for performance reasons. And that approach I'd like to keep too.

My original idea was - each of constructors call register() and create() methods with different parameters - window procedure callback and window classname.

Your idea to overload this methods in each subclass should work, but IMHO it is bad because of duplicating of code. There is lot of redundant code in register and create methods I can't avoid. I can write a wrappers for them and overload those wrappers, then.

But isn't is silly to have such ugly workarounds instead of sane constructors? It is wery hard to follow such not clean code. To help others (and myself) to understand why there is done so, I'll need to comment code, but this still workaround, but not solution.

This is main problem with C (atleast how I see it) - when people looking at code, they see lot of workarounds and quirks hiding actual domain logic. I see no way for C-code to avoid redundancy and code bloat. Thats why I looking forward at D.
August 16, 2006
The real reason why I posted my original message, is that I do not understand purpose of such constructors behavior. I see no benefits of it at all. And can't understand technical limitations (if thats the case) too.

-- 
serg.
August 16, 2006
On Wed, 16 Aug 2006 15:15:49 +0300, Serg Kovrov <kovrov@no.spam> wrote:
> * Oskar Linde:
>> Or, you can reconsider your design. One option is to make a register() method that only the BaseWindow constructor calls. In you child classes, you can overload the register() method anyway you wish.
>
> Yes, I thought about reconsider design to workaround this issue, but I can't find clean solution yet.
>
> Let me clear my design. Obvious hierarchy - a base class for common any-window functionality, and subclasses for common window cases (such top frame, button, reac hedit, etc) which may have more narrow but still generic, and finally end-user-classes for particular application.
>
> All windows classes must register (once) os class with its window procedure, and create a os window *when instancing*. That is one thing I do not want to change. e.g, when I do `new Button("push me")` I have button object ready for action. no need/worry to init it, it should be inited in constructor.
>
> Ok, next. I want unique window procedure for each 'generic' window class. eg BaseWindow FrameWindow, Probably I need to explain more, but do not want to bloat this message. In few words it is for performance reasons. And that approach I'd like to keep too.
>
> My original idea was - each of constructors call register() and create() methods with different parameters - window procedure callback and window classname.

How's this?

import std.stdio;

typedef int function(int i) WNDPROC;

class BaseWindow
{
	void register(char[] cname) { writefln("register(",cname,")"); }
	void create(int function(int) f) { writefln("create(",f(1),")"); }
	
	char[] classname() { return "BaseWindow"; }
	WNDPROC windproc() { return cast(WNDPROC)function int(int i){return i;}; }
	
	this() { register(classname()); create(windproc()); }
}

class FrameWindow : BaseWindow
{
	override char[] classname() { return "FrameWindow"; }
	override WNDPROC windproc() { return cast(WNDPROC)function int(int i){return i*2;}; }
}

void main()
{
	FrameWindow b = new FrameWindow();
	BaseWindow a = new BaseWindow();
}

Regan
August 16, 2006
* Regan Heath:
> import std.stdio;
> 
> typedef int function(int i) WNDPROC;
> 
> class BaseWindow
> {
>     void register(char[] cname) { writefln("register(",cname,")"); }
>     void create(int function(int) f) { writefln("create(",f(1),")"); }
>         char[] classname() { return "BaseWindow"; }
>     WNDPROC windproc() { return cast(WNDPROC)function int(int i){return i;}; }
>         this() { register(classname()); create(windproc()); }
> }
> 
> class FrameWindow : BaseWindow
> {
>     override char[] classname() { return "FrameWindow"; }
>     override WNDPROC windproc() { return cast(WNDPROC)function int(int i){return i*2;}; }
> }
> 
> void main()
> {
>     FrameWindow b = new FrameWindow();
>     BaseWindow a = new BaseWindow();
> }

Thank you, Regan.

This is pretty good looking solution. Seems all solutions are about to avoid using constructors in subclasses at all.

Sadly, constructors appears to be weak in D. I wish some day it will be changed.

-- 
serg.
August 16, 2006
Serg Kovrov wrote:

> Here is my near-real class hierarchy:
>> class BaseWindow {
     uint registerID; // inits to 0
>>   this() {
     if(registerID == 0) // nonzero registerID skips this step
     {
       registerID = register(...);
>>     writefln("register BaseWindowClass");

     }
>>     writefln("create");
>>   }
>> }
>> class FrameWindow : BaseWindow {
>>   this(char[] caption) {
     if(registerID == 0) // nonzero registerID skips this step
     {
       registerID = register(...);
>>     writefln("register FrameWindowClass");
     }
>>     writefln("create %s", caption);
>>   }
>> }
>> class MyFrameWindow : FrameWindow {
>>     this(char[] caption) {
>>         super(caption);
>>     }
>> }

> What I want is that the only constructor called were FrameWindow.this(char[]), to have *only* this:
>> register FrameWindowClass
>> create test

I think caching some value which shows you have already registered should keep any parents from registering again since the child's ctor should always be called first.
August 16, 2006
* nobody:
> I think caching some value which shows you have already registered should keep any parents from registering again since the child's ctor should always be called first.

Sure! This were just a simple example to illustrate hierarchy and purpose of constructors.

-- 
serg.
August 17, 2006
On Wed, 16 Aug 2006 16:43:16 +0300, Serg Kovrov <kovrov@no.spam> wrote:
> * Regan Heath:
>> import std.stdio;
>>  typedef int function(int i) WNDPROC;
>>  class BaseWindow
>> {
>>     void register(char[] cname) { writefln("register(",cname,")"); }
>>     void create(int function(int) f) { writefln("create(",f(1),")"); }
>>         char[] classname() { return "BaseWindow"; }
>>     WNDPROC windproc() { return cast(WNDPROC)function int(int i){return i;}; }
>>         this() { register(classname()); create(windproc()); }
>> }
>>  class FrameWindow : BaseWindow
>> {
>>     override char[] classname() { return "FrameWindow"; }
>>     override WNDPROC windproc() { return cast(WNDPROC)function int(int i){return i*2;}; }
>> }
>>  void main()
>> {
>>     FrameWindow b = new FrameWindow();
>>     BaseWindow a = new BaseWindow();
>> }
>
> Thank you, Regan.
>
> This is pretty good looking solution. Seems all solutions are about to avoid using constructors in subclasses at all.

Or rather you should avoid trying to 'remove' initialisation behaviour from a base class, and instead place optional initialisation in seperate methods which can be overridden.

Constructors are not like ordinary methods, they're always inherited and can only be overridden/removed by going to extremes. This is a much better situation than the alternative which allows you to easily 'forget' to initialise you base class, IMO.

> Sadly, constructors appears to be weak in D. I wish some day it will be changed.

Actually, I disagree. I think the D behaviour is safer and more useful than the alternative. Especially given the fact that it can still handle/solve the problem you had, and does it in a more elegant fashion (IMO) than you were initially going to use, i.e. adding the same lines (with slightly different data) to every sub class constructor (something you might have forgotten to do at some stage)

Regan