some thoughts concerning member name collisions:

(i will also demonstrate a common shortcoming that i personally
 consider a design flaw that exists both in C++ and in Java - it sure
 would be good to avoid the same flaw in PHP - even if MI doesn't
 get into ZE2, keep this in mind for the future)

simply put, the multiple interface paradigm says that a class can provide
an unlimited number of interfaces for already-existing and / or future clients
to operate on. an interface is a contract and it is preferably immutable -
once defined, it is not a good practice to change it. additions and changes
can be accommodated by creating new interfaces. this assures consistency -
you are less likely to break something that relies on a contract if it's final.
but it seems that there is one thing some language designers have overlooked:
two methods with identical signatures (identical names) may have a totally different
meaning in different interfaces, yet it should be possible to multiply implement
both of those in one class. to achieve this, the class implementation has to know
from which interface that ambiguos method was called from. as far as i know,
this is impossible to accomplish in C++ as well as in Java (correct me if i'm wrong).

let me demonstrate (C++, with virtual destructors omitted for simplicity):

// implementation of an animated athlete running,
// so that the result is both an athlete and an animation.
// note that stopping (pausing) the animation is different from
// stopping the athlete from running...

class IAnimation { // the animation interface
 public:
  virtual void run() = 0;
  virtual void stop() = 0;
};

class IAthlete { // the athlete interface
 public:
  virtual void run() = 0;
  virtual void stop() = 0;
};

// so far so good...
class CAthlete: public IAthlete, public IAnimation {
 public:
  virtual void run() { // now what?

indeed, now what? there's no way to tell which interface we were
being cast up to when run() was called... yet as long as the Virtual
Method Table mechanism is concerned, it would actually be possible
to override such ambiguos methods multiply so that they would depend
on the upcast used - in case of non-virtual multiple inheritance as in the
example above the number of VTBL's equals the number of base classes -
the VTBL of the derived class is shared with the first base class and
the rest base classes get one VTBL each. so it would be technically
possible to allow language constructs such as:

class CAthlete: public IAthlete, public IAnimation {
 public:
  virtual void run() {}; // shared between derived class and first base
  virtual void IAnimation::run() {}; // called when upcast to second base

in case of virtual inheritance it would even be possible to differentiate
between all three possible upcasts. however, sadly, C++ does not
allow to explicitly differentiate overrides in different VTBL's. a similar
equivalent seems to be missing from Java, too, if i'm not horribly mistaken...

the effect of this flaw is that developers have to keep track on interface
method names of all interfaces concurrently and manually avoid conflicts.
this is, of course, a big heavy rock on shoulders. all of this also applies
when multiply inheriting implementation, but i chose interfaces so that
my example would make sense in Java.

in PHP we would, of course, only find use for inheriting implementations,
not interfaces. i suggest the following syntax for resolving ambiguities:

class A {
 function foo() {}
}

class B {
 function foo() {}
}

class MI extends A, B {
 function foo() {} // *must* exist, throw compiler fatal otherwise
 function A::foo() {} // may exist, up to the programmer
 function B::foo() {} // may exist, up to the programmer
}

$mi = new MI();
$a = (A)$mi;  // explicit upcast
$b = (B)$mi;  // explicit upcast

$mi->foo(); // calls MI::foo()
$a->foo();  // calls MI::A::foo() if exists, MI::foo() otherwise
$b->foo();  // calls MI::B::foo() if exists, MI::foo() otherwise

since all objects are passed by reference in ZE2, this would
work as expected, that is, quite reasonably well. but what if
someone inherits from MI? let me list the possibilities:

class X extends MI {
 function foo() {}
 function MI::foo() {}
 function MI::A::foo() {}
 function MI::B::foo() {}
}

anybody can see that this syntax would bring *polymorphism* to
a new level and open up neverbeforeseen doors in sense of code reuse.
why should we give up on MI and keep all those doors closed?
i see no harm caused by such syntax to neither compatibility with
single inheritance nor to novice / non-expert PHP programmers -
if they simply don't use features they do not comprehend then PHP
looks like plain-vanilla good-old single-inheritance PHP as they've
always known it. but for the wonderers out there, we would give
a whole new world to explore... and finally, the only certain way
to find out whether a product is successful is to put it on the market...

any comments / corrections are most welcome,

lauri



-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to