Monkey C and monkey do, a reflection about weak references
April 26, 2016
I have recently discovered it is possible to develop apps, faces, widgets and many other things in different Garmin devices using their Connect IQ platform, which is amazing! Some of the compatible devices are Garmin Edge (such as 520, 1000 and Explore 1000), Fēnix 3 and Vivoactive (full list of compatible devices). The possibilities are endless, from writing a simple watch face to making a full app communicating with a smartphone through BLE. They also include a simulator in which you can see your app without physically having the specific device!
The programming language used, Monkey C (and monkey do), seems to be very simple to get started with and, according to them, “there is no better way to learn Monkey C than by jumping right in“, so do not hesitate to check it out 😉
“If you’ve worked with languages such as Java, PHP, Ruby or Python, Monkey C should be very familiar.”
I have started playing a little bit with it and while reading about the language something caught my attention. In their description, they compare Monkey C with the other languages that have been a reference to them and the first comparison is with Java. They say “Also like Java, all objects are allocated on the heap, and the virtual machine cleans up memory (Java through garbage collection, Monkey C through reference counting)“. I had a strange feeling when I read this. Reference counting has an important deficiency: it cannot handle circular references.
The good thing
Fortunately, at some point they realised that. According to their programmer’s guide, from version 1.2.x they introduced weak references in order to solve the reference cycles issue. Textually from their website:
“Monkey C is reference counted, which means the runtime system will free memory when the number of objects referencing that memory decrements to zero. Reference counting allows memory to become available very quickly which is important in low memory environments. The kryptonite of reference counting are circular references.
In these cases, you can use a weak reference. A weak reference is an object that keeps a reference to an object but does not increment the reference count. This means the object reference can be destroyed, and is a case that should be handled.”
The bad thing
The bad thing is that you are using a programming language in which you are not supposed to worry about memory management, but, on the other hand, you have to pay attention if you accidentally create a circular reference. You should use a weak reference in that case.
It can get even worse when, after making some tests, you discover that the Connect IQ simulator is able to detect circular references (using regular strong references, not weak references), but they decided not to automatically collect and free those references and recommend you to use weak references in their programmer’s guide. These are two screenshots of the Garmin Connect IQ simulator after making some tests where I was creating unreachable ciruclar references (yes, I said ciruclar, so did they in the first screenshot):
Actually, the simulator can also crash sometimes because of a single circular reference:
I want to make clear that this is not a criticism only to Monkey C, but also other technologies that may be using weak references to solve reference cycles (like C++ smart pointers or Java).
A reflection about weak references
When I think about weak references they seem amazing, an object reference that is not taken into account when memory freeing/collecting. That means an object will be freed when the only references it has are weak references. Supposedly they have very useful (and unique) uses, like a cache, but I wonder how many programmers know about them and how many have really used them. I have read about using them in Java and how a lot of frameworks should use them in order to avoid memory leaks of objects that the user (the programmer using the framework) is not using anymore. Because, why should someone worry about about notifying another system (or sub-system) that they are not using an object anymore?
In my opinion, this feature tries to cover a lack of architecture. I may be wrong, but that is how I feel about it right now. The fact that one of the motivations of using them is to make it easier for the garbage collector (or reference counter) to collect (or delete) an object when you are not supposed to think about memory management is going against that premise. You have to consciously think about something you are not supposed to think about.