March 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:
>> 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.
March 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:
>> 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!
March 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:
>> 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/igsconnection.d#L148 


-S.


April 02, 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:

somefunction:<(#
  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.

April 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:
>> >
> 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:
>
> somefunction:<(#
>   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

April 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")
1 2 3 4
Next ›   Last »