Extremely Serious Bug in Monkey C!!!

Let's take such class:

class A
{
  hidden var myLocal = "Var from A";

  function do_localModyfication()
  {
    myLocal += " + some modyfication";
  }
}


Then write next class:

class B extends A
{
  // completely by accident 
  hidden var myLocal = "Var from B";

  function test()
  {
    do_localModyfication();
    System.println(myLocal);
  }
}


How do you think what you'll see in the log after B.test() call?

You will see: "Var from B + some modyfication" :confused::p !

And at the end imagine that you are using class for which you have no sources, like View or WatchFace. Please Garmin, tell me if I should pray that my var names are different than yours? Otherwise, your class and mine will explode!

This of course is a BIG BUG and we should only see: "Var from B"

I wonder why Garmin didn't decided to chose eg. C# which is free. Writing in C# if you build your program without warnings you can assume that it will work as intended. In my opinion Monkey C (Java like) it's probably not the best choice and may leads to unstable software.

Peter

  • It looks as exactly the same behaviour. As for me, it is unacceptable, sorry.

    Peter
  • I've looked at this issue a few times, and I must be missing something. You are complaining about how hidden doesn't prevent access to the variable in the base class, but as far as I can tell, _nothing_ in this code accesses A.myLocal and the whether or not myLocal is hidden or not does not have any impact on the behavior of the program. So lets rewind a bit. What _exactly_ are the problems that you are so concerned about?


    I'm afraid I don't understand what problem you are trying to solve by doing this. I see that this would change the definition of extends to be more like Java's implements where it just allows the base to describe the interface for a derived type, but you don't need that in MonkeyC; it is a duck-typed language so interfaces are irrelevant.


    Problem is that class A access myLocal var from class B "thinking" that it is using its own local variable! Subclass B has right to access myLocal from A using A.myLocal and it is OK. But A should never access variables from B.

    Example:

    class A
    {
    hidden var mySum;

    function calculateSum(x)
    {
    mySum = 0;
    for (var localIndexer = 1; localIndexer <= x; localIndexer++)
    {
    mySum += localIndexer;
    }
    return mySum;
    }
    }


    class B extends A
    {
    // class B does not know how class A is implemented but knows that it has nice function calculating Sum
    hidden var mySum;

    function test()
    {
    mySum = calculateSum(1000);
    mySum += calculateSum(100);
    mySum += calculateSum(1);
    return mySum;
    }
    }


    Class B is thinking that it has in mySum quite big number but it has only 1 !

    Again, what problem (exactly) are you trying to avoid? You don't want derived classes to have access to the base class state? Is that it?


    No. Exactly the opposite: alass A can not have access to class variables B.

    Peter
  • the language has a single completely flat 'symbol' space (a symbol with the same name is the same symbol through out the execution instance of the vm, no matter where the symbol occurs)

    I can't make any sense out of this. Could you clarify, or maybe give a test case that demonstrates what you are saying?

    objects seem to be implemented with a simple single-level dictionary for the object instance variables.

    I do see behavior that indicates this to be the case.

    class A
    {
    var v;

    function initialize() {
    self.v = 0;
    }
    }

    class B extends A
    {
    var v;

    function initialize() {
    Sys.println(v);
    A.initialize();
    Sys.println(v);
    self.v = 1;
    Sys.println(v);
    }
    }

    class MyApp extends App.AppBase
    {
    function initialize() {
    App.initialize();

    var b = new B();
    }

    // snip...
    }


    It generates...

    null
    0
    1


    Which indicates that A.v and B.v are actually the same variable. Note that the test case is very similar to that which started this post, so this does tie back to the original issue. If you execute the equivalent code in python, you get the same behavior, so I don't think this is an error in the language, just an error in expectation.

    Travis
  • No. Exactly the opposite: alass A can not have access to class variables B.

    You are expecting A and B to have their own variable named mySum. As far as I can tell, this is not the case. As pointed out above, there is just one variable and they both have access to it.
  • Yes Travis,

    I understand that this compiler has been done that way, maybe because it was easier end faster, perhaps not realizing the consequences but this is just a mistake.
    This feature does not provide anything beyond the possibility of malfunction of the program.

    Peter
  • As far as I can tell, you come from a background with strictly typed languages and are expecting all other programming languages to behave in this way. There is nothing wrong with that. But you have to be willing to accept that many other languages do it this way. You may think it a horrible mistake, but I'm betting the dozens of authors of these languages would be able to convince you you're wrong.

    I've learned a bit from this thread, and I'm glad we're having this discussion. I think it is useful for everyone.

    That said, I did stumble upon this thread on stackoverflow about private variables in python that is interesting. This is the kind of thing that MonkeyC could adopt, remain compatible, and allow for data protection where users want it.

    Travis
  • but I'm betting the dozens of authors of these languages would be able to convince you you're wrong.


    I'm afraid not. I see Travis that you know a lot about Monkey C and this very good news for me because we will live with Monkey C probably for a long time. Assuming that if I find even one example of awakening my fears is to say that Monkey C should be a little bit improved.

    This is real example. I need to extend class Ui.Text. I have some variables at TextEx class level. How can I be sure that the base class does not destroy my variables? I don't know the local names of Text's class variables!

    If I would like to use variable from superclass I will NOT declare it in my class, I will just use it! If I declare variable, it means that I want it to be mine. If such variable exist in a base class then should be compiler error or in base class variable must be decorated by new keyword private.

    Maybe enough could be ask compiler to add some decorators to names of variables declared at class level e.g. <class_name>.<var_name>.

    By the way, in the class Ui.Text I have access to variables locX, locY ... but I have no idea how to read variable justification which I need.

    Peter
  • If I would like to use variable from superclass I will NOT declare it in my class, I will just use it! If I declare variable, it means that I want it to be mine.

    Yup. This is exactly how nearly all strongly-type statically-typed languages I'm familiar with behave (C++, C#, Java). Do you have any experience with dynamically-typed languages (Lua, Ruby, Phthon, ...)?

    If such variable exist in a base class then should be compiler error or in base class variable must be decorated by new keyword private. Maybe enough could be ask compiler to add some decorators to names of variables declared at class level e.g. <class_name>.<var_name>.

    In python, variables with the __ prefix are mangled by the compiler in a way that is similar to what you're describing. Since you don't declare variables in python this convention makes sense. Since you do declare variables in MonkeyC, it probably makes more sense to use private (or local, or something similar).

    Other than readability, there is nothing stopping you from following this convention in your code. The MonkeyC implementation seems to use hidden member variable names that are prefixed with a lowercase m and then camel-caps. If you considered the prefix m[A-Z] to be reserved for the implementation, you'd be very unlikely to step on any toes.

    By the way, in the class Ui.Text I have access to variables locX, locY ... but I have no idea how to read variable justification which I need.

    I think the name is mJustification. It isn't documented, so I don't think you should rely on it. If they implement your proposed fix by adding a way to make variables private, and they applied it here, you wouldn't have access to it anymore. You'd be forced to either inherit a class with state and functions you couldn't use or you'd have to implement the class yourself from scratch.

    Travis
  • I think that asking for something like private and asking for variables with the same name to generate a compiler warning/error are completely valid enhancement requests. It is unlikely that either would break existing code and neither would produce any additional cost.

    But I do think it is totally unreasonable to say that inheriting member data should be removed. It would likely break the entire library of classes that are provided, and it would break tons of code (including the TextEx you're trying to write).
  • Former Member
    Former Member over 9 years ago
    As far as I can tell, you come from a background with strictly typed languages and are expecting all other programming languages to behave in this way. There is nothing wrong with that. But you have to be willing to accept that many other languages do it this way. You may think it a horrible mistake, but I'm betting the dozens of authors of these languages would be able to convince you you're wrong.


    Travis, you're confusing or conflating two entirely orthogonal aspects of programming language design: type checking versus information hiding (object oriented data structure extension).

    A language can be dynamically typed yet still provide for safe, collision-free, extension of data structures; however, this functionality is currently completely missing from Monkey C. Similarly, a language could be statically typed with strong type checking and yet provide a single flat namespace for data structure field names, thus providing no protection from field name collisions - just like the current situation in Monkey C. At least with a type checking system, if the colliding variables are of different types you will get a compiler error; in the absence of type checking, you have to find this problem by way of testing. Too bad there's no test harness capacity for Monkey C. And no ready approach to telemetry, either. (Could someone tell me what the motivating factor for Monkey C in an embedded system is?)