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

From: Date: Thu, 12 Dec 2002 14:38:47 +0000
Subject: Re: [ZEND-ENGINE-CVS] cvs: ZendEngine2 / zend_compile.c
References: 1  Groups: php.dev 
Request: Send a blank email to php-dev+get-92412@lists.php.net to get a copy of this message
Since more feedback may help here i also send this to php-dev At 15:47 08.12.2002, Stanislav Malyshev wrote:
MB>> Therefor i would vote for allowing only decreasing the visibility or force MB>> to keep it. Decreasing visibility contradicts the basic inheritance principle - that derived class "is-a" base class, i.e., basically, it can be used in any place the base class is used. If you restrict methods in derived class, it may lead to a situation where $foo->method() works with base class, but fails with derived class - which is, as I said, against the inheritance principle. As for increasing visibility - I don't see major problem in it. What could be the problem if derived class is allowed to open protected method to public? After all, it could proxy it anyways...
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 (#92412) next »