Thread overview
Proposal
Jul 10, 2004
Matthias Becker
Jul 10, 2004
Ben Hinkle
Jul 11, 2004
Norbert Nemec
Jul 11, 2004
Kris
July 10, 2004
I know that until version 1.0 no extensions to the core language are planed. Someday there

will be a D 2.0 which migth have some extensions. So I start collecting ideas.


Normaly you have to use code like this:

void foo (Base bar)
{
Derived1 derived1 = cast(Derived1)bar;
if (derived1 !== null) {
..
}

Derived2 derived2 = cast(Derived2)bar;
if (derived2 !== null) {
..
}
}

This is very unconvenient. I propose extending switch so you can use it for

type-dispatching:

void foo (Base bar)
{
switch (bar) {
case Derived1 derived1:
..
break;

case Derived2 derived2:
..
break;
}

IMO this would fit perfectly into the language and doesn't cause any ambinguity.


------------------------------------

I have another much more flexible and more extendible idea, but I think it's harder to

implement and I don't know if Walter will like it.


Currently you can overload functions at compiletime. I propose an extension to allow dynamic

overloading that chooses the right function at runtime. Each function-argument can have a

dynamic type additionaly to the static type we already have:

// no changes here; this is used as a fallback
void foo (Base x) {...}

// if the type at runtime is Derived this function is called
void foo (Base @Derived x) {...}



This would allow to write multi-dispatchers in a convenient and easy extendible way:

class Shape            {...};
class Square   : Shape {...};
class Triangle : Shape {...};

bool overlap (Shape a, Shape b) {...}

bool overlap (Shape @Square   a, Shape @Triangle b) {...}
bool overlap (Shape @Triangle a, Shape @Square   b) {...}


As I like functional programming, I'd like to go a step further in direction of patter

matching. I'd like to allow concret values instead of types. So you can write special

handlers for special situations.

enum State {running, stopped}

void handle (State @@running) {...}
void handle (State @@stopped) {...}


This can make code much more easy to read.


This idea is much more powerfull than the switch idea:

class Handler {
void handle (Event e) {...}
}

class ExtendedHandler : Handler {
void handle (Event @AnEvent e) {...}
void handle (Event @AnotherEvent e) {...}
}

class SpecialisedHandler : ExtendedHandler {
void handle (Event @SpecialEvent e) {...}
}


As you see, you can easily extend the proposed dynamic dispatchers, while you can't do this

with the switch-idea.


------------------------------------

While these two ideas don't exclude each other, I don't know, if it would be usefull to have

them both.



July 10, 2004
Matthias Becker wrote:

> I know that until version 1.0 no extensions to the core language are planed. Someday there
> 
> will be a D 2.0 which migth have some extensions. So I start collecting ideas.
> 
> 
> Normaly you have to use code like this:
> 
> void foo (Base bar)
> {
> Derived1 derived1 = cast(Derived1)bar;
> if (derived1 !== null) {
> ..
> }
> 
> Derived2 derived2 = cast(Derived2)bar;
> if (derived2 !== null) {
> ..
> }
> }
> 
> This is very unconvenient. I propose extending switch so you can use it for
> 
> type-dispatching:
> 
> void foo (Base bar)
> {
> switch (bar) {
> case Derived1 derived1:
> ..
> break;
> 
> case Derived2 derived2:
> ..
> break;
> }
> 
> IMO this would fit perfectly into the language and doesn't cause any ambinguity.

Interesting idea but basically this what dynamic function dispatching is for. What if a user added Derived3? They would have to go and add another case to your switch statement.

> ------------------------------------
> 
> I have another much more flexible and more extendible idea, but I think it's harder to
> 
> implement and I don't know if Walter will like it.
> 
> 
> Currently you can overload functions at compiletime. I propose an extension to allow dynamic
> 
> overloading that chooses the right function at runtime. Each function-argument can have a
> 
> dynamic type additionaly to the static type we already have:
> 
> // no changes here; this is used as a fallback
> void foo (Base x) {...}
> 
> // if the type at runtime is Derived this function is called
> void foo (Base @Derived x) {...}
> 
> 
> 
> This would allow to write multi-dispatchers in a convenient and easy extendible way:
> 
> class Shape            {...};
> class Square   : Shape {...};
> class Triangle : Shape {...};
> 
> bool overlap (Shape a, Shape b) {...}
> 
> bool overlap (Shape @Square   a, Shape @Triangle b) {...}
> bool overlap (Shape @Triangle a, Shape @Square   b) {...}
> 

Double-dispatching, or more generally multiple dispatching, is pretty neat and you can google around for various techniques to do it in a single-dispatching language. For example here's a way that uses a table of fcn pointers indexed by ClassInfo.

import std.stdio;

class Shape { };
class Square:Shape { };
class Triangle:Shape { };

void overlapST(Square a, Triangle b) {
  writefln("square triangle");
}
void overlapTS(Triangle a,Square b) {
  writefln("triangle square");
}
void overlapTT(Triangle a,Triangle b) {
  writefln("triangle triangle");
}
void overlapSS(Square a,Square b) {
  writefln("square square");
}

alias void function(Shape a, Shape b) overlapFcn;
overlapFcn[ClassInfo][ClassInfo] overlapFcnTable;
static this() {
  overlapFcnTable[Square.classinfo][Triangle.classinfo] =
cast(overlapFcn)&overlapST;
  overlapFcnTable[Triangle.classinfo][Square.classinfo] =
cast(overlapFcn)&overlapTS;
  overlapFcnTable[Square.classinfo][Square.classinfo] =
cast(overlapFcn)&overlapSS;
  overlapFcnTable[Triangle.classinfo][Triangle.classinfo] =
cast(overlapFcn)&overlapTT;
}

void overlap(Shape x, Shape y) {
  overlapFcn f = overlapFcnTable[x.classinfo][y.classinfo];
  if (f !== null)
    f(x,y);
}

int main() {
  Shape x = new Triangle();
  Shape y = new Square();

  overlap(x,y);
  overlap(y,y);
  return 0;
}

Should the language support this directly? maybe. it would be neat to try it out. It could just end making the language more confusing, though, with overloading rules and overriding rules mixed up together.

> As I like functional programming, I'd like to go a step further in direction of patter
> 
> matching. I'd like to allow concret values instead of types. So you can write special
> 
> handlers for special situations.
> 
> enum State {running, stopped}
> 
> void handle (State @@running) {...}
> void handle (State @@stopped) {...}
> 
> 
> This can make code much more easy to read.
>
> 
> This idea is much more powerfull than the switch idea:
> 
> class Handler {
> void handle (Event e) {...}
> }
> 
> class ExtendedHandler : Handler {
> void handle (Event @AnEvent e) {...}
> void handle (Event @AnotherEvent e) {...}
> }
> 
> class SpecialisedHandler : ExtendedHandler {
> void handle (Event @SpecialEvent e) {...}
> }
>
> As you see, you can easily extend the proposed dynamic dispatchers, while you can't do this
> 
> with the switch-idea.




July 11, 2004
Matthias Becker wrote:

> Currently you can overload functions at compiletime. I propose an extension to allow dynamic overloading that chooses the right function at runtime. Each function-argument can have a dynamic type additionaly to the static type we already have:...

On the on hand, this is a very useful feature. I only have some fears concerning the programming style that follows from it and the effects for large projects:

Reading through code that makes extensive use of dynamic dispatching, it may be really difficult to find the function that is called as some point. In dynamic dispatching, always that function is called which fits the arguments "best". With all the functions possibly being distributed over the whole source, you really have to know very well which function might be defined somewhere.

In principle, you have the same thing for templates already, but here, it is resolved at compile time.

This might not be a reason for not implementing dynamic dispatching, just a feeling, telling me that we should be careful.


July 11, 2004
This kind of thing requires an immense level of care and attention over time; just think back to how unmaintainable all those basic and cobol programs were that used indirect goto's & gosub's ... there really ought to be a law against certain coding practices, just as there is (in some places) a law against many other activities ... <g>


"Norbert Nemec" <Norbert.Nemec@gmx.de> wrote in message news:ccqprc$69i$1@digitaldaemon.com...
> Matthias Becker wrote:
>
> > Currently you can overload functions at compiletime. I propose an extension to allow dynamic overloading that chooses the right function
at
> > runtime. Each function-argument can have a dynamic type additionaly to
the
> > static type we already have:...
>
> On the on hand, this is a very useful feature. I only have some fears concerning the programming style that follows from it and the effects for large projects:
>
> Reading through code that makes extensive use of dynamic dispatching, it
may
> be really difficult to find the function that is called as some point. In dynamic dispatching, always that function is called which fits the arguments "best". With all the functions possibly being distributed over the whole source, you really have to know very well which function might
be
> defined somewhere.
>
> In principle, you have the same thing for templates already, but here, it
is
> resolved at compile time.
>
> This might not be a reason for not implementing dynamic dispatching, just
a
> feeling, telling me that we should be careful.
>
>