When you compile the Gen object, line-by-line errors should display inside of [codebox] and more detailed info inside the Max console window. You can also check the Code window to see if all of your code is compiling properly.
Thanks for your response. I'm not concerned so much about compile errors, but about how to log information to make sure the patch is logically correct. Is there no analog to the Max print object in gen/genexpr?
I don't think there is, and it doesn't really make sense (to me at least) for there to be something analogous to [print]. In gen~ all objects are outputting their value every sample. That would flood a console in a couple miliseconds.
What I'v been doing when I need to probe the signal values at a particular point - connect the gen~ patch to the max world and use a scope~ or number~ object to see what is going on.
If it compiles there are no 'bugs' so to speak. If you're just looking to profile your code, send the data to Max.
Ah, I see. I have wondered the same thing. I use [print] extensively in debugging my Max patches. However, the functionality of [print] is based on accessing a sequential series of events - but there is no explicit sequence of events inside of Gen. Everything in Gen is synchronous. Hence, it's not clear that a Gen [print] object would even be possible.
That said, I sometimes find this a bit confusing because logic often implies a 'before' and 'after'... i.e. certain things need to be evaluated first for the structure to be considered valid. So it seems that a Gen [print] object would be possible. But the creators assure us that the internal functionality of Gen exists in a timeless evernow with no way to access those discreet steps. As such, I view the apparent sequential nature of data flow within Gen as a way to conceptualize logical validity, rather than being a representation of an actual series of step by step calculations.
There absolutely is order within a gen patcher, even within a single sample, for example when using for() statements within a codebox. A print operator would absolutely be a godsend. It could easily be made to have an argument set to print only the first x samples worth of values it's given, in order avoid flooding the Max window.
I guess you could build a function that takes a buffer, a length x, and a trigger value. When it receives a 1 in the trigger it writes the next x samples to a buffer. Instead of printing to the console, it would write to a buffer. You could then look at the contents of the buffer to see what happened over the course of a few seconds, or samples, or whatever.
you could do something like the setup i attached. using a counter you can step through your patch at a faux-slowed down rate. it's possible that this approach isn't applicable to what you're doing, but for example i've used a similar setup to step through a PFFT patch i was building, and it worked perfectly. i didn't print anything from it, i just watched the values going into a number~ and scope~. granted, this takes a lot more setup than a dedicated "print" function within gen might, but i don't know how feasible that would be. like others have mentioned, that's a lot of values to send firing into the console. the buffer~ idea is also a good one. i've considered it but usually end up using this counter idea.
Of course there are many ways to check what's going on in a gen~ patch, it's just a matter of how cumbersome they are. Especially when you have to route things outside the patch (adding extra [out]s, etc.) just to check something trivial. I like the idea of storing values in a buffer though; after the effort of its initial creation, it could probably be something you just paste in quick wherever you need it.
It really blows huge dicks that there's no print function. I absolutely need to have a record of what happened that I can look at after the fact, to see the order things occurred in when they're maybe only a sample apart.
I'm trying to write a custom print function using the buffer idea, but even that is proving difficult to pull off (without a print function)...
A print operator wouldn't make sense; since operations in gen~ run at sample rate, you'd end up generating 44,000 or more console messages per second. There's no way to make sense of that. (Plus, printing to console is a little expensive, and with this many prints per second it could very easily freeze up the patch -- the real reason there's no [print] in gen~ ;-)
The recommended way to debug gen~ patchers is to add an extra outlet, and use ordinary MSP debugging methods in the main patcher. Things like number~, scope~, spectroscope~, etc. Also check out capture~, which not many people seem to know about.
Otherwise, the other option is to make a debug buffer~ and dump signals into that; and again, you can then inspect the buffer~ in whatever way you like. One advantage of using the buffer~ route is that you can control when to capture samples, rather than all the time.
Thanks for providing the official stance on the subject; I'm impressed by how attentive you are to the gen forum, Graham. However, I must continue to make my case for a print operator.
First, the obvious should be stated: that if I had greater expertise in gen a lot of this debugging would be unnecessary, but certainly not all. Also, I should clarify that really the necessity of this functionality is as a genexpr debugger, as inside of a codebox any of the ordering complexities that you could expect from any other language could arise, all within a single sample.
Here are some problems that I personally find with the standard debugging methods you mention:
- They can be quite cumbersome. Having a dedicated debug [out] is, in practice, not as simple as it may seem. What if you need to monitor multiple values at once? Things can get messy fast. Often you'll be looking for something that occurs only one sample out of thousands, surrounded by a sea of 0s. Then latches become necessary. What if 0 is the value you're actually looking for? Then more than just a latch is necessary, and so on.
- A lot of debugging has to do with comparing the exact order of multiple values. None of the ordinary MSP UI objects you mention will easily lend themselves there. Capture~ is an object I was elated to discover and then very quickly left it by the wayside, never to be used again. The problem with it is it's lacking a dump function, which would evolve it beyond being basically just a tedious UI object you have to 'open' to even get any info from, into something that could actually be automated to do anything with those captured numbers you need. Automation is after all the strength of all programming. The 'write' message is just not the same.
- In a maze of nested if() and for() statements, some things may trigger multiple times during one sample and not at all during others. Therefore it would be highly useful to have [print]ed info tagged with the sample during which it occurred. Out of all the suggestions presented, buffer~ is the one option I see that could potentially get me what I need, and I was trying to implement a system which would store values in channel 1 along with corresponding sample numbers (provided by [elapsed]) in channel 2. The buffer~'s length could be variable (probably no more than dozens of samples would be ideal) and once filled, it could dump its contents to have done with them whatever need be. Easier said than done however. Perhaps I'll post my attempts at some point.
- One idiosyncrasy of my setup that makes things even more difficult for me personally is that I deal only with free-form jam sessions. This means that in order to diagnose a rare bug, I absolutely need a log I can refer back to the next day. A jam session might be a half hour long, so there's no way all of my gen data could simply be stored in a buffer~ or capture~ (without a system like the one I just mentioned that is).
As with the capture~ object itself, there's no reason a limit can't be imposed on the number of values being printed, to avoid flooding or slowing things down. And personally I think teleporting the numbers out as raw messages would even be more useful than straight-up printing them; you could always send them to a [print] if you desired anyway.
I hear you, and the feature request is logged as ticket #10206.
I know it could be helpful to drop a print() into a bunch of nested if() blocks in GenExpr, but the trouble is, once there *is* a print() operator, it's going to get used at samplerate (or even faster, if within for() blocks!). Putting a throttle on how much it can store starts to make it more like a circular buffer~ anyway, and as you note, being able to actually store this in a useful way on disk or process it in other ways is more useful than the Max console, which is a kind of black hole. That's why I'm more in favour of re-using existing buffer~ infrastructure.
In the meantime, if it is for debugging in GenExpr, and you want more usefully persistent data such as buffer~s, here's a snippet of code that you could drop into a .genexpr file in your search path, require() and re-use as desired. The only thing you need to add is the buffer~, and it will also capture timestamps if your buffer has 2 channels.
This is gold! Does exactly what I wanted and it actually works! Was a little tricky implementing it in my own patch, owing to a lack of knowledge about using require(). For those uninformed fools like myself, here's how I got it working:
You can't just save the gen patch as a .genexpr file. I had to copy just the relevant code
from the compiled code sidebar and paste it into a text editor, then I saved it as log.genexpr. At the very top of my codebox I wrote
It found the file, however it still didn't understand what debug was referring to until I added a [buffer debug] in my actual gen patch. This doesn't seem to be the way it should be, really. When I call
it finds the function blog() in the required file, so why doesn't it see the buffer definition there?
For future reference, you can type something like, say, "GenExpr require" into that search lozenge in the upper right-hand corner of the patcher window and lots of stuff shows up (which you can search through). Typing "Requiring GenExpr" will bring up the page you no doubt wanted....