Tweak

Path

Actions

Session

Login

Tweak Event Debugging

[This is a modified version of a memo that I sent to the Tweak list]


The Tweak Debugger

If you have updated your Tweak recently you will notice that the debugger looks somewhat different from what it used to:

The top-left pane is what's new and in there you see the top-level messages triggered by an event. In the beginning, there is only one message (the one we're currently debugging in) but as we step over the line saying "self signal: #updateWindowLabel" you will notice that a new message appears in the top left pane:

The message ClassBrowser>>onUpdateWindowLabel was triggered by the event we just signaled and is therefore put under the parent message. When we click on it, we see the new call stack for this message (which hasn't started yet so there isn't very much to see):

If we aren't interested in what precisely happens in a message but only in the messages triggered by it, we can click on the (new!) "complete" button in the debugger. This will simply complete the current message without closing the debugger. For example, let's click on the top-level message and "complete" it, so that we see which other messages are triggered by it:

Using this mechanism we can now find out many interesting things about dependencies between events - here is the event graph which leads to changing the label of a browser window when you click on its system category list:


Event Breakpoints

Often we would like to investigate some particular behavior by starting with a user interaction, say a click. For example, the above debugging sequence shows a class browser's reaction when we click on the system category list. But this already assumes that we know that a click in this list will cause the above method(s) to execute - what if we don't know which method is triggered?

For investigating effects caused by events Tweak supports breakpoints which are triggered by an event. For example, if we get ourselves a class browser and the halo on the system category list, we can see in the red halo menu a "break on" item which lists the various events (for players and their costumes) that we might be interested in.

EventBreakPoints

Note that the list is not exhaustive - it does NOT list any events that this object does not react to. For example, notice that it does not include a mouseDown event - since this is handled inside the scroll target (the drawing area inside the list). However, we do see one of the most interesting events, "cursorChanged" (which, for collections and lists, indicates that the cursor/selection has changed and is the most interesting event here). Once selected, we can click on the list and will see a notifier like here:

EventNotifier

After choosing "debug" we start at the place that is about to trigger the event so that by clicking on "complete" we can see all of the reactions to the cursor changed event.

EventDebugger

Using event break points is one of the ways by which we can track what effects a particular event causes.


Open questions

There are still a whole bunch of open questions for the new debugger. Here are a few that you either need to be aware about or where I'd like some feedback:

How did I get here?

While the above will work fine for situations where something unexpected happens when you do something seemingly harmless (like setting a variable or similar) which may trigger a series of events with effects, it does not yet solve the issue of "how did I get here", e.g., which series of events led to the initial message being triggered.

As far as I can tell there are two potential solutions to this problem, both with its own set of issues. Solution #1 is to keep track of the history of an event so that we would be able to show the parents of the initial message alongside with it. This would work, but it has the potential for generating lots and lots of house-keeping information which could potentially slow down the system and consume quite a bit of resources. In short, unless there is a very obvious way of doing it with very clear tradeoffs I don't like the idea very much.

The second way of getting the information is to start out debugging with a hypothesis. Most of the time we do have an idea about what we did when things go wrong (in fact, one of the first things we learn in debugging is to see if we can repeat the problem reliably) and start debugging from there using the mechanisms described above. It is easy to see that if I have something which happens "when I click this button" all I need to do is start debugging from that click and then have the debugger run up to the point where the error occurs - this gives me exactly the information I am interested in.

The issue that I'm unclear about here is how a user would describe that she is interested in "starting to debug after we click on this button". This is assuming that we don't want to go to a lengthy hacking session, put in a "self halt" and start from there since my feeling is that in order for this to work is has to be very fast and very convenient to use. I am curious if anyone has an idea about how to address this problem.

Ordering of triggered messages

The debugger currently shows the messages in a hierarchy to emphasize causal dependencies. However, that hierarchical view must not be seen as the order in which these messages get executed. In fact, messages always get executed in a breadth-first order, meaning that a hierarchy of messages like:

will be executed in the order

The debugger DOES allow you to execute these messages in arbitrary order mostly because it makes it easier to track cause and effect but as you can see from the above in some ways this is incorrect and may even lead to wrong results (due to different order of execution). The alternatives I could see such as "only allow the message which would be picked by the scheduler" to run, or "run all messages up to the one the user selected" just seem to painful to me. Opinions?

Incomplete messages when closing the debugger

When a debugger closes we need to do "something" about the messages which are either partially completed or haven't been run at all. At this point I am more inclined to just let those messages resume regardless of whether the user chose to abort or to resume (which would only affect the top-level message). This might be supported with a way of killing individual messages (just like complete resumes the message). Any feelings about this?

In any case, if you have had trouble finding out why exactly certain things happen, give the new debugger a try and give some feedback about the things that work and those which don't and what to do about it.