digitalmars.D.learn - super constructors: I can't take it anymore!
- Serg Kovrov (10/33) Aug 16 2006 Hello, everybody,
- Oskar Linde (8/44) Aug 16 2006 If you want to avoid the default constructor to be called in the base
- Serg Kovrov (31/34) Aug 16 2006 Yes, I thought about reconsider design to workaround this issue, but I
- Regan Heath (26/48) Aug 16 2006 How's this?
- Serg Kovrov (8/36) Aug 16 2006 Thank you, Regan.
- Regan Heath (15/43) Aug 16 2006 Or rather you should avoid trying to 'remove' initialisation behaviour
- Serg Kovrov (6/6) Aug 16 2006 The real reason why I posted my original message, is that I do not
- nobody (13/35) Aug 16 2006 if(registerID == 0) // nonzero registerID skips this step
- Serg Kovrov (5/8) Aug 16 2006 Sure! This were just a simple example to illustrate hierarchy and
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 testI 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.
Aug 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: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. /Oskarclass 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 testI 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
Aug 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.
Aug 16 2006
On Wed, 16 Aug 2006 15:15:49 +0300, Serg Kovrov <kovrov no.spam> wrote:* Oskar Linde: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(); } ReganOr, 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.
Aug 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.
Aug 16 2006
On Wed, 16 Aug 2006 16:43:16 +0300, Serg Kovrov <kovrov no.spam> wrote:* Regan Heath: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.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.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
Aug 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.
Aug 16 2006
Serg Kovrov wrote:Here is my near-real class hierarchy:uint registerID; // inits to 0class BaseWindow {if(registerID == 0) // nonzero registerID skips this step { registerID = register(...);this() {}writefln("register BaseWindowClass");if(registerID == 0) // nonzero registerID skips this step { registerID = register(...);writefln("create"); } } class FrameWindow : BaseWindow { this(char[] caption) {}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: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.register FrameWindowClass create test
Aug 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.
Aug 16 2006