On 05/26/2014 04:48 PM, Miller Puckette wrote:
So probably best just to leave it unfixed. I think lots of folks maintaining librares wouldn't want someone else to come in and edit stuff for them.
Well in the case of Hans-maintained libs the only question is whether Hans wants to do it. Those original maintainers are long gone. I think it's a good idea because it turns a crasher into a run-time "no method" error, and people are already sending around "dsp" messages to toggle audio.
For everyone else, here's my hastily written RAQ (rarely asked questions). If I'm wrong about anything please feel free to correct me...
What's the deal?
There's an atomtype named A_CANT. Based on external source code from
svn, only Miller and a few others previously understood what it is for.
Based on looking at the source code, no one previously understood what
it did.
What is A_CANT?
It's a special atom type. It lets you add a method to a class while instructing Pd not to allow that method to be called using Pd's standard message passing system.
How is that different than A_NULL?
A_NULL can be used to tell Pd that a method does not accept any arguments. For example, if you have a method called with the selector "reset" and it doesn't require any arguments, you can use A_NULL when adding that method in your class's setup routine. Theoretically, you might end up with something like this:
class_addmethod(foo_class, (t_method)foo_reset, gensym("reset"),
A_NULL, 0);
That tells Pd not to expect any atoms after the selector "reset". The way Pd is implemented, the user doesn't actually get an error if they send a message with arguments like "reset foo bar"-- it just silently truncates them.
In real code, however, you will just see something more like this
class_addmethod(foo_class, (t_method)foo_reset, gensym("reset"), 0);
because the final "0" is the way to tell Pd "no more args, please". Since we didn't specify any in the first place, it is equivalent to writing "A_NULL" followed by the "0".
On the other hand, A_CANT would tell Pd that the "reset" message should not be handled at all by the message passing system:
class_addmethod(foo_class, (t_method)foo_reset, gensym("reset"),
A_CANT, 0);
In this case if the user sends a "reset" message to an object where the corresponding method has been set with an A_CANT argument, Pd will refuse and output a "bad arguments" error no matter what arguments you give it. (Note: only for the most recent git revision-- older versions will just pass the argument on.)
When would you ever want to use A_CANT?
In situations where you want to define a method but don't want Pd's normal message passing system to access it.
A prime example is Pd's audio engine-- audio objects need a "dsp" method to process a block of audio, but an entire chain of objects must get processed on a regular schedule. (I am guessing) Pd's normal message passing/parsing system creates too much overhead for that task. So instead, Pd builds a big array of pointers to dsp methods when you turn on audio, and it iterates through the array every dsp tick. Instead of passing messages, each method reads/writes to an array of samples.
Then why don't audio objects ever use A_CANT?
Miller's core audio objects now do. Previously, however, they didn't, and so everyone followed suit. That is, up to now every external developer has written their audio objects with a "dsp" method like this:
class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
But as stated above, this is equivalent to an A_NULL argument. While it will restrict any arguments from being passed with a "dsp" message, it still allows the user to send a "dsp" message to the object from within Pd. So, if [osc~] has a "dsp" method that expects arguments that are pointers to arrays of samples, but instead a user sends it a "dsp" message without any arguments, you can guess that the code there won't work correctly. You will get a crash if you (purposely or accidentally) happen to do [dsp(--[osc~].
I'm an external developer. What should I do?
Find the setup routine for all of your tilde objects, and for the dsp method add an "A_CANT, " before the terminating zero. (If you already have an A_CANT there then you should brag so that people can admire your awesomeness.)
So: class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0); becomes: class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), A_CANT, 0);
That will change a potential crasher bug to a user's runtime error.
-Jonathan
cheers M