The "Moldable Debugger"

Debuggers are crucial tools for developing object-oriented software systems as they give developers direct access to the running systems. Nevertheless, traditional debuggers rely on generic mechanisms to explore and exhibit the execution stack and system state, while developers reason about and formulate domain-specific questions using concepts and abstractions from their application domains. This creates an abstraction gap between the debugging needs and the debugging support leading to an inefficient and error-prone debugging effort. To reduce this gap, we propose a framework for developing domain-specific debuggers called the Moldable Debugger.

The Moldable Debugger is adapted to a domain by creating and combining domain-specific debugging operations with domain-specific debugging views, and adapts itself to a domain by selecting, at run time, appropriate debugging operations and views. All in all, the moldable debugger allows you to:

  • craft your custom debugger with custom views and actions, and
  • switch to a contextual debugger dynamically depending on what you need.

A quick example

Have you ever had problems with identifying the difference between an expected result and the actual result when an equality assertion failed in a test case? It can be a daunting task especially if you have to compare two long collections or strings.

Let’s look at an example. The code below simulates a problem in a test that compares two seemingly similar collections. As an exercise, execute this in a Moose image and find where the difference comes from in the debugger. Seriously, please give it a try before going on. It only takes a couple of minutes:

testClass := TestCase subclass: #ATest
      instanceVariableNames: ''
      classVariableNames: ''
      poolDictionaries: ''
      category: 'ATest'.
 testClass compile: 'testEquals
      self
           assert: #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 
49 50 51 51 51 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 
75 76 77 78 79 80 81 81 81 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99)
           equals: #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99)'.
 (Smalltalk globals at: #ATest) new
      setTestSelector: #testEquals;
      debug

Executing the code should raise a debugger like this one:

Did you manage to find why the assertion fails? It’s probably not so easy. If you did manage to find it, did you actually manage both causes? Yes, there are two.

The problem is that the debugger does not make it easy for you to spot these differences. It bombards you with information about all sorts of irrelevant variables while all you care about is a simple diff view between the two compared values. This is recurrent problem that requires dedicated tool support.

To address these kind of problems we worked on the concept of a moldable debugger. The idea is simple: debugging is an analysis activity that has contextual needs, and as such, it benefits from custom tool support. Given that we cannot foresee your specific context, we provide an infrastructure with which you can easily craft your own dedicated debugger.

How does this work in practice?

Let’s turn to our assertion problem. SUnit is an example of a specific library that has specific needs. In our case, if assert:equals: is present in the debugged stack, we want to show a diff view.

To see it in action, re-trigger the debugger with the above snippet, then click on the small triangle from on top of the first pane (the actual user interface is going to change in the future, but for now it is enough to show the concept), and then choose ‘’Available Debuggers/SUnit Debugger’. You will get a new debugger like the one below.

Was it easier to spot the differences? Our guess is yes. If you are still not convinced bellow you can find a screencast comparing this debugger to a generic one.

A hight level view

A tool that matches the context of your problem can provide an order of magnitude productivity increase for solving that problem. Given that debugging is a pervasive activity in software development, having a multitude of custom debuggers around can have a significant productivity impact.

This is a new paradigm that requires a different mindset. First, you have to start utilizing contextual feedback. Second, you have to get comfortable with the idea of crafting your own tools. And third, you have to get used to all this not being expensive.

Bellow you can find a video presenting this idea in a nutshell.

Appart from the SUnit debugger we have implemented a couple of other such dedicated debuggers for PetitParser, Glamour and Announcements.

Debugging PetitParser

PetitParser is a framework that makes it possible to model grammars and parsers as objects that can be reconfigured dynamically. Furthermore, it makes it easy to dynamically reuse, compose, transform and extend grammars.

A generic debugger only provides low-level operations, like stepping over instructions or into function calls. The debugging operations actually needed when working with PetitParser do not map well onto them. Furthermore, when working with PetitParser we need to see contextual information like the source code of grammar productions and the input being parsed. Given the contextual nature of these information it is highly unlikely that generic debuggers will contain them by default.

The solution consists in using a domain specific debugger that presents the parser graphically, and allows you to move smartly between various parsing events (like next time the stream position gets modified).

Debugging Announcements

The Announcements framework from Pharo is a framework providing a synchronous notification mechanism between objects based on a registration mechanism and first class announcements. Since the control flow for announcements is event-based, it does not match well the stack-based paradigm used by conventional debuggers. To solve this problem we have developed a dedicated domain-specific debugger presented bellow (the screencast shows an older version of the debugger).

Getting Started

The GTDebugger implements the idea of a moldable debugger as part of the GToolkit project, and it is by default installed in the latest Moose image. You can download a fresh Moose image from the Moose website.

Authors

Andrei Chiș
Tudor Gîrba

Publications

  1. Andrei Chiş, Oscar Nierstrasz, and Tudor Gîrba. Towards a Moldable Debugger. In Proceedings of the 7th Workshop on Dynamic Languages and Applications, DYLA '13 p. 2:1—2:6, ACM, New York, NY, USA, 2013. DOI PDF 
  2. Andrei Chiş, Tudor Gîrba, and Oscar Nierstrasz. The Moldable Debugger: A Framework for Developing Domain-Specific Debuggers. In Benoît Combemale, David J. Pearce, Olivier Barais, and Jurgen J. Vinju (Ed.), Software Language Engineering, Lecture Notes in Computer Science 8706 p. 102-121, Springer International Publishing, 2014. DOI PDF 
  3. Andrei Chiş, Marcus Denker, Tudor Gîrba, and Oscar Nierstrasz. Practical domain-specific debuggers using the Moldable Debugger framework. In Computer Languages, Systems \& Structures 44 p. 89—113, 2015. Special issue on the 6th and 7th International Conference on Software Language Engineering (SLE 2013 and SLE 2014). DOI PDF 

Blog articles

A first look at the Pharo debugger
A bytecode debugger
Extending the Pharo debugger with custom actions
Last changed by admin on 21 April 2009