Monkey Code Keeper - Tool for developers

Hello, I am currently working on a couple of watchfaces, the last one I have created is My Day 24. And let's say, these tools for developers could be better :) Maybe I am too spoiled from C# and ReSharper plugin, but I wanted to have something better than the current Eclipse SDK.

Currently you can easily make a typo in a variable name, or copy paste some wrong code. The project still compiles and no errors are shown, but the app will crash on a real device in production. It is specially annoying if you have multiple files for each device (one file for Fenix 3, another for Vivoactive) and you change for example the number of parameters of a function, but just in one file. You will not see any crash on your device, but people will report you that it does not work.

So I have created a new tool, a desktop Windows app: http://bit.ly/codekeeper You can select your project folder with .mc files. You can leave this tool opened next to Eclipse, for example on a second monitor. And each time you save an .mc file, the tool will automatically refresh and show the warnings and errors. See screenshots attached.

What's implemented, errors:
- Variable is used, but it was not declared (or it is used before it was declared in the block)
- Function is called, but it was not declared in the same block (on in the global block)
- Function is called, but it has incorrect number of parameters
- Function is called on an instance of a class, but has incorrect number of parameters

Warnings:
- Variable was declared, but not used in the block
- Variable is declared more than once with the same name (for example in a global block and in the function)
- Function is declared more than once with the same number of parameters
- Variable was passed as a parameter of the function, but not used in the function
- Variable was initialized more than once by new keyword

Currently objects are not checked for null reference exception, it would require a better parser (with value propagation into functions and other blocks). I have also not tested yet the new 2.4.0 features like barells and jungle files. Also some weird constructs from the Monkey C language will most likely not work, but you can check it and see it. I have tested multiple Monkey C projects from Github, but there will always be some edge case where it will fail.

You can check the parsed tree (if the code was parsed correctly), or you can edit the list of system functions and variables that should be ignored. And if you are really interested, you will find a donate button on a Help / About screen :)

Download: http://bit.ly/codekeeper

Send me any feedback if you have. community.garmin.com/.../1296466.png community.garmin.com/.../1296467.png community.garmin.com/.../1296468.png community.garmin.com/.../1296469.png community.garmin.com/.../1296470.png
  • Hello, I have updated the tool with some bug fixes. Version 1.0.4 can be downloaded here: http://bit.ly/codekeeper

    Fixed parsing of variables split by a colon inside square brackets:
    [FONT=courier new]var min = [0,0], max = [0,0], lastMin = [0,0], lastMax = [0,0];[/FONT]
  • Interesting tool, it did find a couple of things i cleaned up using your tool. I have some error that i do not know how to fix, and suspect it is not really an error...

    1)
    I have this declared in a separate file for that class.
    static class Utilities {...

    In another file for another class i use a static function as follows:
    Utilities.timeAsStringShort()

    I get an error from code keeper 1.0.3
    Error variable Utilities is not declared...

    I tried adding at the top, but it did not help.
    using Utilities;

    2)
    using Toybox.Communications;
    ...
    Communications.makeWebRequest...
    Error variable Communications is not declared...

    3)
    When trying to report this to you, i tried to copy/paste the error message from your screen, but it does not seem to support copy mode, would be nice if you can select sections of your error report to copy them elsewhere.
  • Hi,

    I have tried the tool also on one of my applications. Here are my observations:

    - inheritance: the tool seems to not correctly resolve inheritance. It claims that I use variables and functions that are not defined in the current block and also not in one of the parent blocks. But this is of course not true, otherwise my code would break. Structure is as follows:

    class A {
    hidden var myvar = null;

    function myfunc() {
    myvar = 1;
    }
    }

    class B extends A {
    function dosomething() {
    myfunc();
    print myvar;
    }
    }


    here the tool tells me, that neither myfunc nor myvar are defined in class B

    - multiple initialization of a variable: following case:

    myvar = 1;
    mycontroller = null;

    if (myvar == 1) {
    mycontroller = new XYZController();
    }
    else if (myvar == 2) {
    mycontroller = new ABCController();
    }

    return mycontroller;


    in such a case the tools says, that mycontroller is initialized multiple times with new, but this is on purpose. Good thing is, it is only a warning

    - I have implemented a utils-class, which is automatically available when running the application. But your tool tells me that the class is not defined. I think in case of monkeyc all files that a project contains are loaded into memory when app starts, so I think if the tool can find the class somewhere in the code files, it can assume that it is available in all other files.

    - static variables are not correctly checked: static variables are claimed to not be used, here an example (singleton pattern):

    class A {
    static var mystaticvar = null;

    static function get() {
    if (A.mystaticvar == null) {
    A.mystaticvar = new A();
    }

    return A.mystaticvar;
    }
    }


    - using-keyword not correctly checked: when including some modules with "using...", those seems to not being recognized:

    using Toybox.StringUtil;

    class A {
    function dosomething() {
    StringUtil.XXX();
    }
    }


    tool claims that StringUtil is not available.

    - one thing that might be very difficult to fix:

    class A {
    function dosomething() {
    getsomething().do();
    }

    function getsomething() {
    return new B();
    }
    }

    class B {
    function do() {
    }
    }


    here the tool is claiming that do() is not defined, because it does not now, that getsomething() is returning instance of B. But I guess it is a big effort to fix it.

    But I have found a lot of things like unused variables and other things where I can remove some unused code, so the tool is really helpful, great job!

    Bye
  • Thank you for your great feedback! That's a lot of issues to fix :)

    System classes
    You can open "Edit system variables" window and add Communications into the first box. The tool currently does not read the list of system classes from the SDK, but at least this should fix the problem in your project.

    Class inheritance
    Yes, this should be fixed. Variables in parent classes are currently not checked. But when trying to save every byte of memory, I did not use a class inheritance in a Garmin project yet :) And I did not see any sample or GIT project that would use it.

    Multiple initialization of a variable
    Yes, a warning is shown, because this is very often a source of problems and errors. It can be done by mistake, it can be from the old unused code. It can be a source of memory leaks.

    Static classes and static variables
    In most cases, this is a bad coding practise and you should not use it :) Also calling of static variables and methods of global classes can be up to 8x slower, than calling these methods directly on an instantiated object in Monkey C.

    Using keyword not correctly checked
    It is checked, but it seems that only in some specific cases. When a '.' character is in the definition, it is not parsed correctly. I will look on it. But this can also be probably fixed by the "Edit system variables" window.

    Calling on an instance of an object...
    No way this can be fixed without a proper compiler / interpreter :)
  • System classes
    "using"-keyword

    I think reading the list of system classes is not necessary here. The assumption can be that if somebody is putting line "using Toybox.XXX" the tool can assume, that class XXX is available.

    Class inheritance:

    I am not aware of how MonkeyC is handling inheritance internally, but my hope is that it is optimized in such a way that using it does not slow down performance big tiem on apps. I am using inheritance a lot as I do not want to duplicate code, as this increases memory usage. Maybe a Garmin developer can put some light on this :)

    Static classes and static variables

    I was not aware that static things are much slower than objects. Where did you get this information from?

    Bye
  • Would like to gain a better understanding of some comments made here. While there are sometimes arguments made on the basis of pure OO principles, are there really performance issues also?

    1) static classes slower - is this really true?

    2) class inheritance - efficiency, memory usage etc - some insights how this is implemented in monkey C and how it might effect memory use in particular.
  • I don't work at Garmin, and I don't know exactly how it's implemented :) Maybe Brian.ConnectIQ can help more.

    But based on my observations, global variables and global methods are very slow. The interpreter needs to search through all fields, until the correct one is found. This is especially painful if you want to read a global array of values. Each access to that array is slow. Sometimes is faster to copy the global array into the local array, then read the values in a for cycle, and then copy the result back into global array.

    You can read my article here: How to improve Connect IQ app performance

    There are lot of useful links inside to other discussions on this forum: Website links
    Especially these: Code tuning, Performance DOs and DONTs, Constants in a prg file
    This talk from the Summit was also very useful: Effective monkey C
  • I can imagine that access to global properties/methods is slow, as this is also not a good way of programming at all. But it is difficult to believe that oop principles like inheritance or static classes are causing issues. It would be very interesting to get some information on that from a Garmin developer.

    Bye
  • Thanks for the tips Tomas, such info does tend to be spread all over, these are a nice handy reference.

    note that in the monkey c reference document it mentions using a $. prefix to improve performance in access to globals.
    I tend to find i have a small number of functions that are handy to be available in more than one class so I use a few global functions.
    The bulk of the code is in standard classes.

    // Call global helloFunction
    $.helloFunction();
  • Globals are slow to access because they are the last location to be searched, but as noted in the Effective Monkey C presentation you linked, and the reference document as mentioned by Ottawa, using the $. prefix will compile a direct lookup in globals and will skip searching the local object chain. This should speed up access to globals significantly.

    Class searching is also covered in Effective Monkey C. variable lookups will start from the closest reference and search out. Locals will be the fastest to access, followed by Class members, with each level of inheritance that must be traversed adding additional overhead. If an element with a deep level of inheritance is being accessed frequently you may want to cache it in a local variable.