digitalmars.D - Cumulative
- Steve Teale (24/24) Feb 24 2014 25 years ago, when I was trying to write some sort of library to
- Steve Teale (4/28) Feb 24 2014 Sorry, I had two foo()s in the 'example'. What I meant was
- Gary Willoughby (17/41) Feb 24 2014 This exists but it's not automatic.
- qznc (12/22) Feb 24 2014 I think the point is that the super.foo() call is enforced.
- qznc (5/29) Feb 24 2014 Sounds a little like the :after mechanism of the Common Lisp
- Dan Olson (9/13) Feb 25 2014 Yes! - and CLOS came from my all time favorite playland, the Symbolics
- Tofu Ninja (6/30) Feb 24 2014 This is something that I have wished for as well. If it was
- Nick Sabalausky (6/15) Feb 24 2014 I've often wished for something like that when working on OO-heavy
- Namespace (35/35) Feb 24 2014 Maybe:
- Tofu Ninja (24/59) Feb 24 2014 This is not good enough, this makes the "extend" optional on
- Tofu Ninja (5/9) Feb 24 2014 In the case where it would be needed to be called at the
- Shammah Chancellor (10/20) Feb 24 2014 So far as I'm understanding this thread, Steve Teale is asking for a
- Steve Teale (8/17) Feb 25 2014 It's a bit more specific than 'from other places in the program',
- Shammah Chancellor (6/26) Feb 25 2014 If I was understanding properly, you were suggesting that the code
- Steve Teale (9/11) Feb 25 2014 OK, it's at britseyeview.com/cumulative.txt.
- Shammah Chancellor (10/19) Feb 25 2014 It seems we were talking about different things. I thought you were
- Steve Teale (10/15) Feb 25 2014 However, I now realize you can do better in D. The base class
- Jesse Phillips (4/12) Feb 24 2014 When I've had a need for base classes to call super class
- Shammah Chancellor (6/9) Feb 25 2014 Sounds like a good reason to use unittests to me. The compiler can't
- Tofu Ninja (7/16) Feb 25 2014 As unit tests are optional, they are in no way an enforcement.
- Leandro Motta Barros (21/41) Feb 26 2014 Hello,
- Steve Teale (12/17) Feb 26 2014 Yes we went through that, if you go back a page you'll find a
- Shammah Chancellor (7/25) Feb 27 2014 Actually, D has the ability to walk the object hierarchy at compile
- Steve Teale (3/11) Feb 27 2014 Yes, I'd been thinking about tagging them at least.
- Steve Teale (47/61) Mar 06 2014 I've also noticed from the responses, and from responses to
- Nick Sabalausky (32/43) Mar 06 2014 FWIW, I don't think that's really the prevailing attitude towards OO. OO...
- Steve Teale (9/25) Mar 06 2014 Thanks Nick. A voice of sanity. Interestingly I'd decided on the
- John Colvin (2/30) Mar 07 2014 How would these plain functions be different from final ones?
- Steve Teale (9/10) Mar 07 2014 You would be able to redefine them in a derived class using
- John Colvin (4/8) Mar 07 2014 So the compiler would choose which function is called based on
- Steve Teale (21/30) Mar 07 2014 Twould be as in this C++, is that what you mean?
- Steve Teale (37/38) Mar 07 2014 I can get tantalizingly close to what I want using the extra
- Shammah Chancellor (6/78) Mar 07 2014 I understand what you want to do, I'm just not sure I understand the
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (15/35) Apr 02 2014 Yes. This is "inner virtual functions" as opposed to "outer
- Steve Teale (20/35) Apr 02 2014 I had gone some distance along that course. A virtual function to
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (31/35) Apr 02 2014 Yeah, I think it would need language support to be worthwhile in
25 years ago, when I was trying to write some sort of library to go with Walter's C++ compiler, I had a wish, and it still pops into my head from time to time. What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method. extend void foo() // Declared in base class as cumulative void foo() { (cast(BaseClass) this).foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff } I think also that it might be necessary for the base class function to return on behalf of the derived method as opposed to to it. Does this make any sense? Steve
Feb 24 2014
On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:25 years ago, when I was trying to write some sort of library to go with Walter's C++ compiler, I had a wish, and it still pops into my head from time to time. What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method. extend void foo() // Declared in base class as cumulative void foo() { (cast(BaseClass) this).foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff } I think also that it might be necessary for the base class function to return on behalf of the derived method as opposed to to it. Does this make any sense? SteveSorry, I had two foo()s in the 'example'. What I meant was extend void foo() // Declared in base class as cumulative {
Feb 24 2014
On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:25 years ago, when I was trying to write some sort of library to go with Walter's C++ compiler, I had a wish, and it still pops into my head from time to time. What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method. extend void foo() // Declared in base class as cumulative void foo() { (cast(BaseClass) this).foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff } I think also that it might be necessary for the base class function to return on behalf of the derived method as opposed to to it. Does this make any sense? SteveThis exists but it's not automatic. class Foo { void foo() { ... } } Class Bar : Foo { override void foo() { super.foo(); // Call parents method. ... } }
Feb 24 2014
On Monday, 24 February 2014 at 08:55:02 UTC, Gary Willoughby wrote:On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:I think the point is that the super.foo() call is enforced. Is it possible to write a cumulative annotation to detect missing calls? Example: class Base { cumulative void foo() {} } class Bar : Base { void foo() {} // compile error, no super.foo() call } It should probably get another name like overrideExtends.What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method.This exists but it's not automatic.
Feb 24 2014
On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:25 years ago, when I was trying to write some sort of library to go with Walter's C++ compiler, I had a wish, and it still pops into my head from time to time. What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method. extend void foo() // Declared in base class as cumulative void foo() { (cast(BaseClass) this).foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff } I think also that it might be necessary for the base class function to return on behalf of the derived method as opposed to to it. Does this make any sense? SteveSounds a little like the :after mechanism of the Common Lisp Object System (CLOS). They also have :before, if your extra code should run before the super-call. The third variant is :around, which is like the default overwriting in D et. al.
Feb 24 2014
"qznc" <qznc web.de> writes:Sounds a little like the :after mechanism of the Common Lisp Object System (CLOS). They also have :before, if your extra code should run before the super-call. The third variant is :around, which is like the default overwriting in D et. al.Yes! - and CLOS came from my all time favorite playland, the Symbolics Lisp Machine with its version of OOP called Flavors. See page 25 section 1.12 Method Combination and you will see a zoo of ways to combine methods from a class ineritance hierarchy. ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-602.pdf A fun read. I wonder what David Moon is doing today? -- Dan
Feb 25 2014
On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:25 years ago, when I was trying to write some sort of library to go with Walter's C++ compiler, I had a wish, and it still pops into my head from time to time. What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method. extend void foo() // Declared in base class as cumulative void foo() { (cast(BaseClass) this).foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff } I think also that it might be necessary for the base class function to return on behalf of the derived method as opposed to to it. Does this make any sense? SteveThis is something that I have wished for as well. If it was automatically inserted, it would only make sense for it to be useable on functions with no return and no arguments. If it was just enforcement then it wouldn't matter. Something that does do this currently is default constructors.
Feb 24 2014
On 2/24/2014 3:41 AM, Steve Teale wrote:extend void foo() // Declared in base class as cumulative void foo() { (cast(BaseClass) this).foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff } I think also that it might be necessary for the base class function to return on behalf of the derived method as opposed to to it. Does this make any sense?I've often wished for something like that when working on OO-heavy stuff. Some virtual funcs are intended to always be called by all overriding functions, but without a way to enforce that, it becomes a scary error-prone choice of API design. And trying to design your way around that limitation can be a pain.
Feb 24 2014
Maybe: ---- extend void foo() { ... } ---- would force you to use super.foo() and otherwise gives an error? ---- class Foo { void foo() { // ... } } class Bar : Foo { extend void foo() { // compiler will force you (opposed to override) that you call super.foo() but it isn't important where. You can call it at the end or at the start or wherever you wish. } } ---- Maybe we could also reduce the super.FUNCTION with "super" as for base class constructors. Or to distinguish we could name it "base": ---- class Foo { void foo() { // ... } } class Bar : Foo { extend void foo() { base(); /// will be rewritten to super.foo(); } } ---- The latter is of course for the "lazy" people. :)
Feb 24 2014
On Tuesday, 25 February 2014 at 00:18:47 UTC, Namespace wrote:Maybe: ---- extend void foo() { ... } ---- would force you to use super.foo() and otherwise gives an error? ---- class Foo { void foo() { // ... } } class Bar : Foo { extend void foo() { // compiler will force you (opposed to override) that you call super.foo() but it isn't important where. You can call it at the end or at the start or wherever you wish. } } ---- Maybe we could also reduce the super.FUNCTION with "super" as for base class constructors. Or to distinguish we could name it "base": ---- class Foo { void foo() { // ... } } class Bar : Foo { extend void foo() { base(); /// will be rewritten to super.foo(); } } ---- The latter is of course for the "lazy" people. :)This is not good enough, this makes the "extend" optional on overridden functions. What it needs to be is a way to ensure that if your function is overridden by a base class that it is guaranteed to be called by the new function. Something like this class A { extendable void foo(){} } class B : A { override void foo(){}// compilation error, super.foo not called } This makes it non-optional. You have to call super.foo if you want to override foo. Also, in some cases it is not enough just to ensure that it is called, some times you will want to make sure that it is called at the beginning or end of the function. Though this is harder to get right, not really sure how it would work with returns. Also I think it would make sense for something like this to be transitive. For instance in the above example, the new foo should also be extendable or else the guarantee breaks.
Feb 24 2014
On Tuesday, 25 February 2014 at 00:55:55 UTC, Tofu Ninja wrote:Also, in some cases it is not enough just to ensure that it is called, some times you will want to make sure that it is called at the beginning or end of the function. Though this is harder to get right, not really sure how it would work with returns.In the case where it would be needed to be called at the beginning or the end of the new method. The compiler might be able to implicitly add it in itself, similar to how super(); is implicitly added to the beginning of overridden constructors.
Feb 24 2014
On 2014-02-25 01:08:47 +0000, Tofu Ninja said:On Tuesday, 25 February 2014 at 00:55:55 UTC, Tofu Ninja wrote:So far as I'm understanding this thread, Steve Teale is asking for a way to inject code before and after a call to a function from other places in the program. E.g. Write some function foo, write some function bar, and specify that any time foo is called, bar should be called immediately after *automagically*. The reason this hasn't been done in any language I'm aware of is because you can solve the same problem using existing polymorphism, and it's a horribly awful design practice to have hidden code like that. -S.Also, in some cases it is not enough just to ensure that it is called, some times you will want to make sure that it is called at the beginning or end of the function. Though this is harder to get right, not really sure how it would work with returns.In the case where it would be needed to be called at the beginning or the end of the new method. The compiler might be able to implicitly add it in itself, similar to how super(); is implicitly added to the beginning of overridden constructors.
Feb 24 2014
On Tuesday, 25 February 2014 at 03:13:23 UTC, Shammah Chancellor wrote:So far as I'm understanding this thread, Steve Teale is asking for a way to inject code before and after a call to a function from other places in the program. E.g. Write some function foo, write some function bar, and specify that any time foo is called, bar should be called immediately after *automagically*. The reason this hasn't been done in any language I'm aware of is because you can solve the same problem using existing polymorphism, and it's a horribly awful design practice to have hidden code like that.It's a bit more specific than 'from other places in the program', and anyway, once you've accepted virtual functions, you've accepted 'automagic' ;=) I'm writing a little example program that illustrates what I'm getting at, and I'll post it somewhere when I'm through. Steve
Feb 25 2014
On 2014-02-25 10:23:31 +0000, Steve Teale said:On Tuesday, 25 February 2014 at 03:13:23 UTC, Shammah Chancellor wrote:If I was understanding properly, you were suggesting that the code should be executed even for instances of the base class. There's some automagic that's good, that sounds like a vile thing to have to debug when you take over for somebody else. -S.So far as I'm understanding this thread, Steve Teale is asking for a way to inject code before and after a call to a function from other places in the program. E.g. Write some function foo, write some function bar, and specify that any time foo is called, bar should be called immediately after *automagically*. The reason this hasn't been done in any language I'm aware of is because you can solve the same problem using existing polymorphism, and it's a horribly awful design practice to have hidden code like that.It's a bit more specific than 'from other places in the program', and anyway, once you've accepted virtual functions, you've accepted 'automagic' ;=) I'm writing a little example program that illustrates what I'm getting at, and I'll post it somewhere when I'm through. Steve
Feb 25 2014
On Tuesday, 25 February 2014 at 10:23:32 UTC, Steve Teale wrote:I'm writing a little example program that illustrates what I'm getting at, and I'll post it somewhere when I'm through.OK, it's at britseyeview.com/cumulative.txt. I think enforcement of the call to super.handleCommand() would get most of the way down the road. More could be done if the compiler inserted the super call, and maintained an implicit class member equivalent to my 'cmdResult' that could be tested in override implementations of handleCommand(). But I think that is OTT. Steve
Feb 25 2014
On 2014-02-25 11:04:23 +0000, Steve Teale said:OK, it's at britseyeview.com/cumulative.txt. I think enforcement of the call to super.handleCommand() would get most of the way down the road. More could be done if the compiler inserted the super call, and maintained an implicit class member equivalent to my 'cmdResult' that could be tested in override implementations of handleCommand(). But I think that is OTT. SteveIt seems we were talking about different things. I thought you were suggesting the following: void main() { auto a = new Base(); int[] a1 = [ 0, 1, 2, 3 ]; foreach (int n; a1) a.dealWithCommand(n); <-- Calls all the extension methods. }
Feb 25 2014
On Tuesday, 25 February 2014 at 11:04:24 UTC, Steve Teale wrote:On Tuesday, 25 February 2014 at 10:23:32 UTC, Steve Teale wrote:However, I now realize you can do better in D. The base class needs to define an array of delegates. It appends its handler to the array, then derived classes each append their handler. The append is done like: handlers ~= &Red.handleCommand; Am I right in thinking that this makes the calls non-virtual? Anyway, the result is I think exactly what I wanted. The example is at britseyeview.com/cum2.txt. SteveI'm writing a little example program that illustrates what I'm getting at, and I'll post it somewhere when I'm through.OK, it's at britseyeview.com/cumulative.txt.
Feb 25 2014
On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:extend void foo() // Declared in base class as cumulative void foo() { super.foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff }When I've had a need for base classes to call super class functions, I certainly wanted a way to enforce it. I just don't know if it would just lead to other OOP design problems.
Feb 24 2014
On 2014-02-25 05:38:15 +0000, Jesse Phillips said:When I've had a need for base classes to call super class functions, I certainly wanted a way to enforce it. I just don't know if it would just lead to other OOP design problems.Sounds like a good reason to use unittests to me. The compiler can't possibly deal with all the different ways you might want to enforce an OOP pattern in a particular program. Introducing more keywords does not seem like a fix. -S.
Feb 25 2014
On Tuesday, 25 February 2014 at 11:13:44 UTC, Shammah Chancellor wrote:On 2014-02-25 05:38:15 +0000, Jesse Phillips said:As unit tests are optional, they are in no way an enforcement. And for library writers(which is who this idea is mainly for I think), writing unit tests to try and test user written code seems a little unreasonable, especially as they don't have access to the code :/When I've had a need for base classes to call super class functions, I certainly wanted a way to enforce it. I just don't know if it would just lead to other OOP design problems.Sounds like a good reason to use unittests to me. The compiler can't possibly deal with all the different ways you might want to enforce an OOP pattern in a particular program. Introducing more keywords does not seem like a fix. -S.
Feb 25 2014
Hello, I'm coming late to the discussion, but I believe that you can use the following idiom to achieve the same results in a different way: class C { // This is not overridable public final void doStuff() { doSomethingWhichNeverChanges(); doExtraStuff(); } protected void doExtraStuff() { // This one can be overridden } } Or did I miss something? Cheers, LMB On Mon, Feb 24, 2014 at 5:41 AM, Steve Teale <steve.teale britseyeview.com>wrote:25 years ago, when I was trying to write some sort of library to go with Walter's C++ compiler, I had a wish, and it still pops into my head from time to time. What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method. extend void foo() // Declared in base class as cumulative void foo() { (cast(BaseClass) this).foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff } I think also that it might be necessary for the base class function to return on behalf of the derived method as opposed to to it. Does this make any sense? Steve
Feb 26 2014
On Wednesday, 26 February 2014 at 13:30:15 UTC, Leandro Motta Barros wrote:Hello, I'm coming late to the discussion, but I believe that you can use the following idiom to achieve the same results in a different way:Yes we went through that, if you go back a page you'll find a post I did that makes the thing work better using a class variable in the base class that is an array of delegates. That way you don't have to do super, super, super back to root, you just have to iterate over the delegates until you find one that accepts the command. It does just what I wanted to do in the first place without compiler assistance ;=). Steve
Feb 26 2014
On 2014-02-26 16:05:19 +0000, Steve Teale said:On Wednesday, 26 February 2014 at 13:30:15 UTC, Leandro Motta Barros wrote:Actually, D has the ability to walk the object hierarchy at compile time, and generate a function call containing all the super classes's handleCommands. You could also even tag them with an attribute a switch, or bunch of if's to avoid function calls. -S.Hello, I'm coming late to the discussion, but I believe that you can use the following idiom to achieve the same results in a different way:Yes we went through that, if you go back a page you'll find a post I did that makes the thing work better using a class variable in the base class that is an array of delegates. That way you don't have to do super, super, super back to root, you just have to iterate over the delegates until you find one that accepts the command. It does just what I wanted to do in the first place without compiler assistance ;=). Steve
Feb 27 2014
On Thursday, 27 February 2014 at 21:44:20 UTC, Shammah Chancellor wrote:On 2014-02-26 16:05:19 +0000, Steve Teale said: Actually, D has the ability to walk the object hierarchy at compile time, and generate a function call containing all the super classes's handleCommands. You could also even tag them accept to be able to generate a switch, or bunch of if's to avoid function calls. -S.Yes, I'd been thinking about tagging them at least.
Feb 27 2014
On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:25 years ago, when I was trying to write some sort of library to go with Walter's C++ compiler, I had a wish, and it still pops into my head from time to time. What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method.OK, I'm back to this because I have done quite a bit of work trying to get to what I wanted. I have converted my app so that it conforms roughly to the above, as a test.I've also noticed from the responses, and from responses to associated questions, that OOP has become almost a dirty word in the D community. It's old fashioned and slow. So if you're in that camp, you can stop reading now. I need to handle signals of some sort - let's say just represented by an int. In my base class I define a method final void handleSignal(int), to which all signals are directed. In the same place there's a virtual function bool signalHandler(int). The base class also has a data member bool delegate(int)[] handlers. In classes Base, Intermediate, and Leaf, say, the constructor has a statement: handlers ~= &Base.signalHandler; handlers ~= &Intermediate.signalHandler; handlers ~= &Leaf.signalHandler; The final handleSignal() method in the base class just traverses the array, calling each delegate in turn until one returns true, and then throws an exception or something if none of them do. This works nicely. A lot of duplicate code in my original handler functions is eliminated. Any particular leaf class just has to cover the cases peculiar to it's own requirements. Intermediate classes just deal with their generic cases, and the base class handles all the signals that all leaves require. The compiler doesn't help to ensure that the 'handlers ~=' bit is present in all constructors, so I thought I would be clever, and provide some mixin template or template function that all the constructors in the hierarchy used, so that it was a fairly simple thing to insist on, even if only by example. But I have been frustrated in this desire. A member function like final void doMyThing(string CLASSNAME)() { handlers ~= mixin("&"~CLASSNAME~".signalHandler;"); } defined in the base class does not work, because the compiler complains about the type of the this pointer being Base, despite the fact that I am being explicit about the class name. Attempts from other directions like calling back down the super() chain don't work because I can't have anything but declarations in a mixin template, and a super() call inside a template function called by the constructor fails because the call is not in a constructor. Anyone have any bright ideas about how this could be regulated? I can't say forced, because I think the compiler would have to do that. Steve
Mar 06 2014
On 3/6/2014 11:48 AM, Steve Teale wrote:I've also noticed from the responses, and from responses to associated questions, that OOP has become almost a dirty word in the D community. It's old fashioned and slow. So if you're in that camp, you can stop reading now.FWIW, I don't think that's really the prevailing attitude towards OO. OO definitely has its uses and benefits (and outside performance-critical sections its performance is perfectly fine), it's just not the one-size-fits-all mold to force everything into like it often got treated as ~10 or so years ago. Even the entity/component-based systems that I mentioned games commonly use are still frequently employing OO, too (ex: Unity3D uses an entity/component-based design for game objects, but the API for dealing with the game object, components, etc is still an OO API). Entities, metaprogramming, OO - none of these are "either/or" deals, just as OO doesn't actually try to replace procedural programming but is rather used together with it.I need to handle signals of some sort - let's say just represented by an int. In my base class I define a method final void handleSignal(int), to which all signals are directed. In the same place there's a virtual function bool signalHandler(int).[...]Anyone have any bright ideas about how this could be regulated? I can't say forced, because I think the compiler would have to do that.A stab in the dark here, but can you just add "bool delegate(int)[] additionalHandlers" as a required parameter for your base class's constructor? Then the base class's constructor does "this.handlers ~= additionalHandlers" Or maybe something like this?: class MyBaseClass { bool addHandlersCalled = false; bool delegate(int)[] handlers; /// Subclasses must call this in their ctor. protected void addHandlers(bool delegate(int)[] handlers) { this.handlers = handlers; addHandlersCalled = true; } invariant() { assert(addHandlersCalled); } }
Mar 06 2014
On Friday, 7 March 2014 at 02:15:44 UTC, Nick Sabalausky wrote:On 3/6/2014 11:48 AM, Steve Teale wrote:Thanks Nick. A voice of sanity. Interestingly I'd decided on the argument to the constructor while programming in bed last night. The change of fashion is very noticeable though - structs for everything seems to be a mantra these days. I have started to wonder if the two styles could be bridged somewhat if we had the default class method type as virtual, and then 'plain' functions as well as final ones. Steveclass MyBaseClass { bool addHandlersCalled = false; bool delegate(int)[] handlers; /// Subclasses must call this in their ctor. protected void addHandlers(bool delegate(int)[] handlers) { this.handlers = handlers; addHandlersCalled = true; } invariant() { assert(addHandlersCalled); } }
Mar 06 2014
On Friday, 7 March 2014 at 06:18:47 UTC, Steve Teale wrote:On Friday, 7 March 2014 at 02:15:44 UTC, Nick Sabalausky wrote:How would these plain functions be different from final ones?On 3/6/2014 11:48 AM, Steve Teale wrote:Thanks Nick. A voice of sanity. Interestingly I'd decided on the argument to the constructor while programming in bed last night. The change of fashion is very noticeable though - structs for everything seems to be a mantra these days. I have started to wonder if the two styles could be bridged somewhat if we had the default class method type as virtual, and then 'plain' functions as well as final ones. Steveclass MyBaseClass { bool addHandlersCalled = false; bool delegate(int)[] handlers; /// Subclasses must call this in their ctor. protected void addHandlers(bool delegate(int)[] handlers) { this.handlers = handlers; addHandlersCalled = true; } invariant() { assert(addHandlersCalled); } }
Mar 07 2014
On Friday, 7 March 2014 at 09:04:29 UTC, John Colvin wrote:How would these plain functions be different from final ones?You would be able to redefine them in a derived class using override to tell the compiler that it was intentional. Final would remain as-is - final. I think Walter made a good choice for the times when he chose to have functions virtual by default, but a system programming language should allow you to do dangerous things if you give the compiler your permission. Steve
Mar 07 2014
On Friday, 7 March 2014 at 09:43:07 UTC, Steve Teale wrote:On Friday, 7 March 2014 at 09:04:29 UTC, John Colvin wrote:So the compiler would choose which function is called based on the compile-time type of the class reference, instead of the runtime type info? Inheritance without the polymorphism.How would these plain functions be different from final ones?You would be able to redefine them in a derived class using override to tell the compiler that it was intentional.
Mar 07 2014
On Friday, 7 March 2014 at 10:05:56 UTC, John Colvin wrote:On Friday, 7 March 2014 at 09:43:07 UTC, Steve Teale wrote:Twould be as in this C++, is that what you mean? #include <iostream> class A { public: void foo() { std::cout << "This is A\n"; } }; class B: A { public: void foo() { std::cout << "This is B\n"; } }; int main() { A* a = new A(); B* b = new B(); a->foo(); b->foo(); } My, it was painful writing that!On Friday, 7 March 2014 at 09:04:29 UTC, John Colvin wrote:So the compiler would choose which function is called based on the compile-time type of the class reference, instead of the runtime type info? Inheritance without the polymorphism.How would these plain functions be different from final ones?You would be able to redefine them in a derived class using override to tell the compiler that it was intentional.
Mar 07 2014
On Friday, 7 March 2014 at 02:15:44 UTC, Nick Sabalausky wrote:On 3/6/2014 11:48 AM, Steve Teale wrote:I can get tantalizingly close to what I want using the extra constructor argument. In the base class I define a template function: string initString(T)() { return "string sname = \""~T.stringof~"\"~to!string(++nextOid);" "HandlerDelegates[] ahdg = [ HandlerDelegates( &"~ T.stringof~".notifyHandler, &"~T.stringof~".undoHandler)];"; } Then in the leaf class constructor I can just do: mixin(initString!Arrow()); super(aw, parent, sname, AC_ARROW, ACGroups.SHAPES, ahdg); Sadly the compiler does not complain if I comment out the leaf notifyHandler() method, cos its virtual, and there's one in its parent class. Does contract programming to provide a way to say that some function definition is required? This is where I'd like to be able to say: class Base { // Method is called directly, but unlike a final // method it can be overidden in a derived class. direct bool notifyHandler(...) { ... } } class Inter { // Kill the warning about hiding the base class method with override override bool notifyHandler(...) { ... } } As a side benefit, I think that mixing in a string generated by a template function gives me a way of generating something approximating a mixin template that allows more than just declarations - insertion of parameterized code at compile time ;=) Steve
Mar 07 2014
On 2014-03-06 16:48:44 +0000, Steve Teale said:On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:I understand what you want to do, I'm just not sure I understand the use-case. However, you may be interested in this code for some ideas for possible alternatives: https://github.com/schancel/gameserver/blob/master/source/connections/ gsconnection.d#L148 -S.25 years ago, when I was trying to write some sort of library to go with Walter's C++ compiler, I had a wish, and it still pops into my head from time to time. What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method.OK, I'm back to this because I have done quite a bit of work trying to get to what I wanted. I have converted my app so that it conforms roughly to the above, as a test.I've also noticed from the responses, and from responses to associated questions, that OOP has become almost a dirty word in the D community. It's old fashioned and slow. So if you're in that camp, you can stop reading now. I need to handle signals of some sort - let's say just represented by an int. In my base class I define a method final void handleSignal(int), to which all signals are directed. In the same place there's a virtual function bool signalHandler(int). The base class also has a data member bool delegate(int)[] handlers. In classes Base, Intermediate, and Leaf, say, the constructor has a statement: handlers ~= &Base.signalHandler; handlers ~= &Intermediate.signalHandler; handlers ~= &Leaf.signalHandler; The final handleSignal() method in the base class just traverses the array, calling each delegate in turn until one returns true, and then throws an exception or something if none of them do. This works nicely. A lot of duplicate code in my original handler functions is eliminated. Any particular leaf class just has to cover the cases peculiar to it's own requirements. Intermediate classes just deal with their generic cases, and the base class handles all the signals that all leaves require. The compiler doesn't help to ensure that the 'handlers ~=' bit is present in all constructors, so I thought I would be clever, and provide some mixin template or template function that all the constructors in the hierarchy used, so that it was a fairly simple thing to insist on, even if only by example. But I have been frustrated in this desire. A member function like final void doMyThing(string CLASSNAME)() { handlers ~= mixin("&"~CLASSNAME~".signalHandler;"); } defined in the base class does not work, because the compiler complains about the type of the this pointer being Base, despite the fact that I am being explicit about the class name. Attempts from other directions like calling back down the super() chain don't work because I can't have anything but declarations in a mixin template, and a super() call inside a template function called by the constructor fails because the call is not in a constructor. Anyone have any bright ideas about how this could be regulated? I can't say forced, because I think the compiler would have to do that. Steve
Mar 07 2014
On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:What I wanted was functions that were declared in a base class as 'cumulative', or something similar. They would have been generally like virtual functions, except that any derived class that wanted to do something extra - as opposed to something different, would simply define an 'extend', and just specify the extra code. The compiler would then automatically add a call to the same function in whatever base class last defined or extended the method. extend void foo() // Declared in base class as cumulative void foo() { (cast(BaseClass) this).foo(); // Compiler does this for you // similar to changing a light bulb ;=) // the extra stuff } I think also that it might be necessary for the base class function to return on behalf of the derived method as opposed to to it. Does this make any sense?Yes. This is "inner virtual functions" as opposed to "outer virtual functions" (C++). The successor to Simula, BETA (http://daimi.au.dk/~beta/), has this. Simula has this in the constructor of a class (which syntactically is the body), but BETA has the concept everywhere: statements1; inner; statements2; When you specialize a function/class the extra stuff you add is replacing the "inner" statement (and can provide it's own "inner"). It provides for better encapsulation/enforcing invariants.
Apr 02 2014
On Wednesday, 2 April 2014 at 14:23:57 UTC, Ola Fosheim Grøstad wrote:On Monday, 24 February 2014 at 08:41:06 UTC, Steve Teale wrote:I had gone some distance along that course. A virtual function to handle events examined the event to see if it could deal with it. If it could not, it called a 'specificHandler' virtual function. But that approach only works if you have a hierarchy of known depth, when specificHandler only gets called for the leaf classes. Later, I have had the constructors of derived classes add a handler delegate to a list of potential handlers maintained in the base class. The actual handler in the base class is a final method that simply iterates that list until some derived class handles the event, or throws if none do. But both of these approaches are clumsy compared to what I would like to see. It would help if D had 'direct' class methods (as opposed to final or virtual), as then I think it would be more straightforward to generate the delegate list. I'm pleased to see though that some other languages have noted this deficiency. SteveYes. This is "inner virtual functions" as opposed to "outer virtual functions" (C++). The successor to Simula, BETA (http://daimi.au.dk/~beta/), has this. Simula has this in the constructor of a class (which syntactically is the body), but BETA has the concept everywhere: statements1; inner; statements2; When you specialize a function/class the extra stuff you add is replacing the "inner" statement (and can provide it's own "inner").
Apr 02 2014
On Wednesday, 2 April 2014 at 18:14:46 UTC, Steve Teale wrote:But both of these approaches are clumsy compared to what I would like to see.Yeah, I think it would need language support to be worthwhile in the long run. I think it makes a lot of sense for constructors that the superclass has the first and last word in what the object should look like. E.g. let subclasses populate an array in their "inner-clauses" and let the superclass verify it or compile it into something efficient. However, it does require a sensible super class design since you don't override virtual functions, but merely extend them.I'm pleased to see though that some other languages have noted this deficiency.Yup, I am not sure if the inner clause was in Simula I in 1963, but I believe it must have been present in Simula67. It was also used for prefixing of blocks in Simula so that you could open "libraries" by turning a class into a scope. E.g. class MyToolkit begin integer filehandler; methods like print() filehandler = openstuff(); inner; closestuff(filehandler); end // and use it as MyTookit begin print() // file is open, we can print here end As Simula was Bjarne Stroustrup's influence for C++ he really does not have an excuse for not adopting this stuff. ;-) Well, I guess RAII is his version of "inner"… If you had virtual types as class members then I guess you could emulate inner with RAII like patterns. (By instantiating the class rather than doing a function call and let the constructor and destructor wrap the "inner")
Apr 02 2014