Re: [ZEND-ENGINE-CVS] cvs: ZendEngine2 / zend_compile.c

From: Date: Fri, 13 Dec 2002 00:06:18 +0000
Subject: Re: [ZEND-ENGINE-CVS] cvs: ZendEngine2 / zend_compile.c
References: 1 2  Groups: php.dev 
Request: Send a blank email to php-dev+get-92441@lists.php.net to get a copy of this message
[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


« previous php.dev (#92441) next »