Tutorial 5: Message Order and Debugging
Introduction
Open the tutorial.
This tutorial is focused on message ordering – the sequence in which messages are passed from object-to-object and how objects generate them. We will also use some of the debugging tools in Max to determine how a patch is running.
Max patches often seem to have everything happening at once; in reality, messages are produced and acted upon in a specific order. In order to make patches that operate correctly, we need to understand the order that things are occur, and how to control complex matrices of actions.
Right-to-left, bottom-to-top
Take a look at the tutorial patcher. This file has a number of small patches that we will use to learn about the rules that messages follow. Click on top-most button in the top-left patch; it seems that all three of the connected button objects fire simultaneously. This is an illusion – messages are sent down the patch cables in a sequential order.
The easiest way to see this in action is to use some of the debugging tools in Max. You'll notice that the top row of patches in the tutorial have small red circles with numbers in them covering the patchcords. These are called watchpoints (specifically - breakpoint watchpoints). When we debug our patcher, we can use these watchpoints to stop the execution of the patch at a specific point. This is done by enabling the Max Debugger. Select Enable Debugging from the Debug menu. Once debugging is enabled, these watchpoints will help us see the way messages are passed in our patcher.
Click on the topmost button in the left-hand patch. Instead of the immediate "flash" of all the button objects lighting up, the rightmost patchcord begins blinking red. In addition, a window opens called the Debug Window. Looking at the window, you can see what kind of information it gives us. The window tells us that a bang message has been intercepted by a watchpoint; moreover it tells us which watchpoint was tripped (in this case, watchpoint #1), the name of the patcher and what class of object the sending and receiving object was (in this case, both are button objects). Select Step from the Debug menu (or press Shift-Command-T). You will see that the middle cord flashes; select Step again and you will see that the left-most cord flashes. Select Step once more to finish our patch trace. When the outlet of an object is connected to more than one inlet, the messages are sent in right-to-left order.
But what happens when the receiving objects are stacked vertically (and therefore at the same horizontal position)? With debugging still enabled, click on the topmost button in the middle patch on the top row. As the watchpoints fire, select Step from the Debug menu. When we Step through the patch, we see that the bottom-most button receives its message first, follow by the middle, then the top. So, we can see that Max has two levels of ordering: right-to-left, then bottom-to-top.
There is one more twist to message ordering, and that is the effect of messages that cause more messages to be generated. The third patch illustrates the issue. Click on the top-most button and Step through the order of the messages. By tracing through this matrix of button objects we see that messages travel through the entire depth of one message chain before sending a message to the next "branch" of objects. Notice that the Debug Window shows you the length of each message chain in a branch; it only clears when a branch has been completed.
Therefore, the message-ordering rules in Max are:
1. Right-to-left, then bottom-to-top.
2. Depth-first traversal of connected objects.
Note that, for determining the right-to-left or bottom-to-top ordering, it is the location of the connected object, not the location of the patch cords, that determines the message route.
As an exercise, create a new matrix of button objects, with both vertical and horizontal arrays of button objects (perhaps using the Align option from the Arrange menu), and multiple depths of objects. Use comment boxes to number the boxes in the order you think they will fire then trace the patch. Do this until the message ordering becomes second nature!
Select Disable Debugging from the Debug menu, and let's look at the other patches in the tutorial patcher.
More message ordering
Sometimes it is inconvenient to match the spatial order of the patch with our desired result. In the bottom row of patches, the left-most patch is well structured: it is cleanly laid out, and has the number boxes in ascending numerical order from left to right. If we wanted the messages to go from low to high, it is also wrong; when we click the top button, we see the numbers come out in reverse order in the Max window. This is because the message boxes are receiving bang messages in right-to-left order.
The next patch shows a corrected version of this patch, using a new object: bangbang. This object takes an incoming message and produces bang messages from its outlets in right-to-left order. The number of outlets is determined by the argument to bangbang (in this case, the 3 argument produces three outlets). The outlets are connected to the message boxes in the appropriate order; when we click on the top button, the Max window displays the messages in the preferred order.
Notice that the outlets of bangbang fire in right-to-left order, mimicking the message ordering of the patch itself. Most objects with multiple outlets will follow this rule: output is from the right-most outlet to the left-most outlet.
Use the bangbang object makes the message order explicit; that is, it forces the messages to follow a specific path regardless of spatial orientation, and lets us place objects anywhere we want in the patch, knowing that they will be triggered in deterministic order based on which outlets we trigger them from. Another message that provides explicit ordering is the trigger object. The trigger object accepts input, and outputs messages based on its arguments. The arguments determine the type of output, with options of l (for list), b (for bang), i (for integer), s (for symbol – a text message) and f (for floating-point number). You can also use specific integers, floating point numbers or symbols as constant outputs.
The next patch contains two message boxes with the integer 90. If we click on the one connected directly to the print objects, the Max window displays the typical right-to-left ordering of messages. However, if we click on the message box connected to the trigger object, we see that we can control the output to print in left-to-right (reversed) order. The sent messages are all printed as the integer 90, since our arguments for trigger were are of type i (integer).
The next patch to the right also uses an incoming integer message (90), and is connected to a trigger object (using the object abbreviation: “t”). However, in this case, three different arguments are used. When we click on the message box, we see that the output of the three outlets are all different, matching the difference in arguments. The right-most outlet, with argument of type i (integer), produces an unchanged 90 output. The middle outlet, set to type f (for floating-point), casts the incoming message to its floating-point equivalent (90.000000) and sends it to the print object. Finally, the left-most outlet, of type b (bang), accepts the incoming message but turns it into a bang. So, in addition to making the message order explicit, the trigger object can do type conversion of messages.
The right-most patch shows the use of constant values within the trigger object. When we change the floating-point number box to any number, the trigger object again converts the incoming number, but also includes a number of symbols (text messages) that are used as constant values. We also see that the incoming message did not change the output of the bang outlet – a bang is a bang, regardless of incoming message type.
Now would be a good time to build some more button matrices, but combining them with trigger and bangbang objects, and labeling them with their expected message order.
The trouble with loops
The final patch in our tutorial file is a set of four button objects all interconnected in a loop. When we click on any of the button objects, the system comes to a halt with a stack overflow error. Why did this happen? Remember that Max does a depth-first prioritization of messages. However, a looped patch construction has an infinite depth, and therefore cannot be properly parsed. One button sends to the next, which sends to the next, which sends to the next, which sends to the first, triggering the cycle all over again. Click OK to get rid of the error dialog. When a stack overflow occurs, Max shuts off its scheduler to prevent anything else from happening; once we've found the problem and corrected it in our patch (e.g. by disconnecting one of the button objects in the loop), we can turn the patch "on" again by clicking Resume under the Edit menu.
Conclusion
A deep understanding of message ordering rules is necessary to create properly functioning patches. The right-to-left, bottom-to-top, depth-first order is the implicit rule for message passing, but you can use objects like bangbang and trigger to make the ordering explicit. In all cases, however, you need to watch out for structural loops – they are literal patch-killers!

See Also

Name Description
bangbang Send a bang to many places, in order
trigger Send input to many places, in order