[Stas answered you in a very thorough and accurate way, and since it took several hours since I started composing this reply and the time I actually sent it, I cut it down to minimum]

Marcus,

I (as well as basically all major OO languages I can think of) disagree with you.
OO and inheritance are TOTALLY about 'is a'. If you want a quick verification for this, look for any serious comparison between inheritance and aggregation, and you'd see that inheritance is about 'is a', and aggregation about 'has a'. You may argue about which is better, but there's no argument about what inheritance relationship is.

Saying "Visibility is about information hiding not showing" is wrong. It has truth to it, as in, visibility is about information hiding, but it most certainly is also about information showing. When you write a class that exposes a certain interface (i.e., its public methods), inheriting from that class means that the derived class should satisfy the same API as the parent (and possibly more). Inheritance is about specialization. Your derived classes must be able to implement the same API as their parents, and possibly (usually) more, specialized features.

I agree with Stas that increasing visibility is not such a necessity. It's not useful in most cases, and I haven't had the opportunity to ever take advantage of it myself. However, increasing visibility does not, in any way, violate the principles of OO. Derived classes can still interface with code designed for their base classes, and that's what matters. Therefore, I see no problem in allowing increase in visibility. Remember - private elements pretty much do not exist for anything outside the class. In turn, this means that 'overriding' a private method with a public method is allowed, since if it wasn't allowed, it would mean that the private method IS exposed in some way to the child, if only for the fact it's preventing the child class from using this name. With protected, the parent class is declaring explicitly that the derived class may alternate functionality. It's up to the derived class to decide whether this alternative functionality should be publicly available or not. The important thing is that it's available.

Decreasing visibility, however, breaks the most fundamental rule of inheritance. Objects from derived classes can no longer be considered to also of the type of their parent classes. In Java, for instance, it would mean that you cant up-cast the object safely (or, in other words, send an object of type Square to a function that knows how to deal with Rectangles), which would seriously break the language fundamentals.
I agree with Stas too that a typecasting operating is a non issue in PHP. We have no kind of compile-time linkage at all - all of our method calls behave like 'virtual' method calls. Since we have a single path inheritance tree like Java, we can safely avoid the headaches C++ bumped into with its wide variety of ugly typecast operators.

We could, I suppose, implement a Java-equivalent typecasting operator in some way, so you'd be able to call Rectangle's area() instead of Square's. I'm not sure how necessary this is, and how feasible it is, but most of all - I don't see how it relates in any way to the visibility discussion we had here...

Bottom line - I'm not sure why you're under the impression that "visibility hiding is king" and that "the 'is a' concept is not important". With inheritance, it's simply the other way around.

Zeev

At 16:38 12/12/2002, Marcus Börger wrote:
Let me say two things first:
1) Visibility is about information hiding not showing.
2) You are wrong about 'is-a' in general. Our main problem here is that we
do not have a typecast operator.

1) Visibility modifiers are for information hiding. That is you can hide certain
implementation details. Each class has three interfaces: i) the interface
accessible from any other scope. ii) the interface accessible from any
derived class

Suppose you are going to design an encryption framework. Then you surely will
first design an interface. In php you will create an abstract class to accomplish
this. Then you will implement general features which will handle unencrypted
content and such. Also you may implement general key handling. In the class
hierarchy you will make all acess to uncencrypted content protected or even
private starting from here. Doing this you ensure that no user and in case of
private even no derived class can access unencrypted content.
=> Only information hiding = decreasing visibility.

Or suppose you have a class for content handling and you will base encryption on
top of this. Then you will derive the encryption handling from content handling and
mark unencrypted acess methods/properties as private.
=> Only information hiding = decreasing visibility.

Note the different motivations for deriving classes above.

More examples could be made but that's not the point here. The point is that
there is a need for decreasing visibility. And personally i do not see any need
for increasing visibility besides the 'is_a' comment.

When increasing the visibility you show functionality being hidden in a base class.
Most often this is done to fix wrong class design or to missuse baseclasses in ways
they are not designed for.

2) For our current implementation you are partly right with your comment on
'is_a' because you cannot use a parent interface of a class. But your comment
does not hold since 'is_a' does not work even without visibility in php like you want
it.

Example without visibility:

class A {
function println($msg) {
echo "$msg\n";
}
}
class B {
function println() {
// whatever...
}
}

when in this example you work on B instances with A's protocol you will see
that B's println does not recognize $msg. => When deriving classes in a typed
language an overloaded method must accept the same input and must return
the same output.

Maybe we decide that for PHP this is not a problem since we simply ignore
this fact what is possible in a loosely typed language. Otherwise deriving checks
would become much more complex since we need to store the input and check
for that, too. At least we must count required, optional and "..." input parameters
then.

In the above example I assumed we had inheritance working as in typed OO
languages. I further assumed that when having B as a subclass of A and b
as instance of B, b can be used with protocol A by using a typecast. That is:
is_a(b, A) === true implies that even methods made private in B can be used
with protocol A if they are public there. It does not imply that you can use A's
protocol without typecasting b to A. When in this scenario all methods are linked
dynamically we have what we want: by calling a method from b typecysted to A
the overwritten method from class B is being invoked.

Immediate conclusion: I tried changing visibility in other languages and read again
about it in some books. I came to the conclusion that both increasing and
decreasing works in some languages but only found hints for the need of
information hiding (decreasing visibility).

Example:
#include <iostream>

class A {
public:
virtual void pub() { cout << "A::pub" << endl; };

protected:
virtual void pro() { cout << "A::pro" << endl; };
};

class B: public A {
protected:
virtual void pub() { cout << "B::pub" << endl; }; // You can also make this private

public:
virtual void pro() { cout << "B::pro" << endl; };

};

int main(int argc, char **argv) {
B *b = new B();
b->pro();
dynamic_cast<A*>(b)->pub();
// b->pub(); B::pub is protected
delete b;
}

In this C++ example dynamic_cast is used for "is_a". When dynamic_cast<X*>(p)
returns NULL the variable p is not of type X or one of it's parent.

Problem: Increasing the visibility is a bit strange (at least for me) but current php
design can only handle increasing or keeping visibility. Further more current
implemetation of 'is_a' does not work when decreasing visibility is allowed.

Solution: Force keeping visibility or or allow increasing as of now.

Next step: We can handle decreasing visibility by modifying zendengine.
When calling a method we must look into the calling scope and see what
visibility a function has for the situation a method is called dynamically from
a classes scope or the scope of one of its parents. This requires walking on
the class hierarchy what is slow but i do not see a solution to avoid it and
handling privates correctly.

Next Next Step: typecast

I think the engine can be expanded by a typecast function or operator: Say "cast".
For eaxample "cast($obj,$class)" will result in an error if $class is not a parent of
$obj's class or equals $obj's class itself. When it is successfull we would simply
set the the visibility to the visibility of the method in that scope. When $class does
not have the method being called then it is even an error if $obj's class has. This
is affected by the way privates work and affetcs that also (inheriting privates or not).

As a sideeffect we could handle decreasing the visibility without a need for walks
on the inheritance tree.

Problem left: Input/Output checking. As php is a loosely typed language i suppose
we are not going to verify that derived classes overload methods correctly. Said this
we perhaps even make the input protocol of abstract methods optional (no need for
the brackets).

Sorry for the late answer :-)

regards
marcus

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

Reply via email to