Protected variable vs protected function

Hi,

When extending a class, I can override a protected function of the base class, and other functions of the base class will then use the function from my derived class.

class TestSlave extends TestMaster {
    protected function printInternal() {
        System.println( "Slave" );
    }
    public function initialize() {
        TestMaster.initialize();
    }
}

class TestMaster {
    protected function printInternal() {
        System.println( "Master" );
    }
    public function print() {
        printInternal();
    }
}

However this seems to work only for functions. For member variables, I have to declare them public for this to work, like in the example below. If I'd declare _text as protected in this example, the compiler will tell me "Attempting to override protected variable from a parent class.".

class TestSlave extends TestMaster {
    var _text = "Slave";
    public function initialize() {
        TestMaster.initialize();
    }
}

class TestMaster {
    var _text = "Master";
    public function print() {
        System.println( _text );
    }
}

Is there any sense behind this difference between functions and variables? Can I achieve this for a variable without making it public?

  • This makes sense. If you already have _text in the base class and it's not private then you can use it. In your example instead of redeclaring it, add this to TestSlave.initialize:

    _text = "Slave";

  • But what is the sense in being able to override a member variable when it is public, but not being able to do it when it is private?

  • You haven't demonstrate 

    override a member variable when it is public
  • You haven't demonstrate 

    So, basically the code I posted initially has no declaration in front of the var, hence they are public. And that code works, it compiles, and when instantiating the Slave and calling print(), it will print "Slave". When instantiating the Master and calling print(), it will print "Master".

    However, when I declare the var protected in the Master, I cannot override it anymore, I get the compiler error.

    That part is what does not make sense to me.

    It is not a big deal, just something I noticed when trying to refactor and optimize my code a bit.

  • You haven't demonstrate 

    override a member variable when it is public

    But they did, right in the example.

    - "override" means to redeclare a member M in child class C which also exists in base class B, in such a way that C's M will be used even by B. In this case C = TestSlave and B = TestMaster. (Yeah I'm aware this doesn't work for member variables in most languages. but it apparently works for Monkey C)

    - the default member visibility is public, which means that in the example, _text is public in both TestSlave and TestMaster.

    It seems to work as expected:

    var t = new TestSlave();
    t.print(); // prints "Slave"

    This makes sense. If you already have _text in the base class and it's not private then you can use it

    Actually, the error only occurs when _text is protected in the base class. If_text is private in the base class there is no error (at compile time or runtime), but TestSlave.print() actually prints "Master". (Which makes sense since private members aren't inherited or overridden)

    EDIT: sorry I realize this is the point you were trying to make, so it's kinda dumb for me to reiterate it as if you meant otherwise

    class TestSlave extends TestMaster {
        var _text = "Slave";
        public function initialize() {
            TestMaster.initialize();
        }
    }
    
    class TestMaster {
        private var _text = "Master";
        public function print() {
            System.println( _text );
        }
    }
    
    // ...
    var t = new TestSlave();
    t.print(); // Master
    

    Also, if you disable type checking, there's no compile-time error when _text is protected in the base class. In this case, there's no error at runtime either. In this case, TestSlave.print() prints "Slave". This is also arguably expected behaviour, except for the fact that the type checker doesn't like this pattern.

    (:typecheck(false))
    class TestSlave extends TestMaster {
        var _text = "Slave"; // if type checking were enabled, would produce: "ERROR: Attempting to override protected variable from a parent class.""
        public function initialize() {
            TestMaster.initialize();
        }
    }
    
    class TestMaster {
        protected var _text = "Master";
        public function print() {
            System.println( _text );
        }
    }
    
    //...
    var t = new TestSlave();
    t.print(); // prints "Slave"
    

  • I think that the opposite of what you think is happening. Try with private instead of protected.

    Anyway this is more of a basic programming question, less of Monkey C. 

    Redeclaring a variable in the child class is not like overriding a method. If you already declared it in the base class as protected, you should just use it from the child class. As I wrote, you can set it from the constructor of the child class. Even nicer is if you pass it to the constructor of the base class (though that effectively makes it "abstract" or you will need to pass it from outside as well)

  • I think that the opposite of what you think is happening. Try with private instead of protected.

    Read my reply above

  • Redeclaring a variable in the child class is not like overriding a method. If you already declared it in the base class as protected, you should just use it from the child class.

    But when I have it declared as public in the base class, overriding it works just fine. It only does not work when it is declared as protected. That is what stroke me as odd.

  • It only does not work when it is declared as protected. That is what stroke me as odd.

    This does work if you disable type checking which is also interesting

  • Ok, right, you convinced me. Sounds like a compiler bug indeed