www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Cumulative

reply "Steve Teale" <steve.teale britseyeview.com> writes:
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
next sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
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?

 Steve
Sorry, I had two foo()s in the 'example'. What I meant was extend void foo() // Declared in base class as cumulative {
Feb 24 2014
prev sibling next sibling parent reply "Gary Willoughby" <dev nomad.so> writes:
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?

 Steve
This exists but it's not automatic. class Foo { void foo() { ... } } Class Bar : Foo { override void foo() { super.foo(); // Call parents method. ... } }
Feb 24 2014
parent "qznc" <qznc web.de> writes:
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:
 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.
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.
Feb 24 2014
prev sibling next sibling parent reply "qznc" <qznc web.de> writes:
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?

 Steve
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.
Feb 24 2014
parent Dan Olson <zans.is.for.cans yahoo.com> writes:
"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
prev sibling next sibling parent "Tofu Ninja" <emmons0 purdue.edu> writes:
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?

 Steve
This 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
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
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
prev sibling next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
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
parent reply "Tofu Ninja" <emmons0 purdue.edu> writes:
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
parent reply "Tofu Ninja" <emmons0 purdue.edu> writes:
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
parent reply Shammah Chancellor <anonymous coward.com> writes:
On 2014-02-25 01:08:47 +0000, Tofu Ninja said:

 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.
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.
Feb 24 2014
parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
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
next sibling parent Shammah Chancellor <anonymous coward.com> writes:
On 2014-02-25 10:23:31 +0000, Steve Teale said:

 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
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.
Feb 25 2014
prev sibling parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
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
next sibling parent Shammah Chancellor <anonymous coward.com> writes:
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.
 
 Steve
It 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
prev sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
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:
 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.
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. Steve
Feb 25 2014
prev sibling next sibling parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
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
parent reply Shammah Chancellor <anonymous coward.com> writes:
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
parent "Tofu Ninja" <emmons0 purdue.edu> writes:
On Tuesday, 25 February 2014 at 11:13:44 UTC, Shammah Chancellor 
wrote:
 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.
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 :/
Feb 25 2014
prev sibling next sibling parent reply Leandro Motta Barros <lmb stackedboxes.org> writes:
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
parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
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
parent reply Shammah Chancellor <anonymous coward.com> writes:
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:
 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
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.
Feb 27 2014
parent "Steve Teale" <steve.teale britseyeview.com> writes:
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
prev sibling next sibling parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
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
next sibling parent reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
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
next sibling parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
On Friday, 7 March 2014 at 02:15:44 UTC, Nick Sabalausky wrote:
 On 3/6/2014 11:48 AM, Steve Teale wrote:

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); } }
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. Steve
Mar 06 2014
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
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:
 On 3/6/2014 11:48 AM, Steve Teale wrote:

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); } }
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. Steve
How would these plain functions be different from final ones?
Mar 07 2014
parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
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
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
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:
 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.
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.
Mar 07 2014
parent "Steve Teale" <steve.teale britseyeview.com> writes:
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:
 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.
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.
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!
Mar 07 2014
prev sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
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
prev sibling parent Shammah Chancellor <anonymous coward.com> writes:
On 2014-03-06 16:48:44 +0000, Steve Teale said:

 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
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.
Mar 07 2014
prev sibling parent reply "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
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
parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
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:

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").
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. Steve
Apr 02 2014
parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
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