Sometimes pure data is really doing my head in and feels so counterintuitive
At the leftt there are three message boxes "-" "kick" and "hat " ..in Pure data world these are are (implicit)symbols.
The select module however does not identify these because there is NO symbol selector , this feels so counter intuitive .
When sending a list through a list store and retrieve the individual elements , a symbol selector is automatically added since the select module accepts these
-
Symbols explicit
-
[route] only matches to the 1st element, and passes the rest of the message. It would more properly need to handle lists... in the case of a symbol, it's kinda pointless to send it to route, as you can only have a bang output, and this is not the purpose of that object. It is the point of the [select] object though.
I don't think this is an issue for [route] at all. Having said that, [route] has many issues. It has inconsistencies (like how it doesn't trim the symbol selector). I don't debate about its bad design. That's why I wrote [route2]
and I also have [routetype] and [routeall]... in [route2] it can manage a list message and route the rest.
This is not about the language concept and design, it's about the object design. I see design problems in many object, but hey, help file is there to show how the object works one way or another, even if it has inconsistencies.
-
@porres said:
[route] only matches to the 1st element, and passes the rest of the message. It would more properly need to handle lists... in the case of a symbol, it's kinda pointless to send it to route, as you can only have a bang output, and this is not the purpose of that object. It is the point of the [select] object though.
I'm thinking of the Ruby "principle of least surprise," by which a behavior of an object or function may be justifiable, but suboptimal because it can easily trip users up.
Which is nicer for users? They both just work the way you'd think (match it, and it passes through), or to enforce subtle distinctions and thereby get in the user's way? (Not saying here that it's always a good thing to let sloppy thinking slide, but, neither is it always good to rub the user's nose in design decisions.)
Symbols aren't "the point" of [route], but why then does [route] not automatically strip the "list" tag? Least surprise would be to just do the thing the user wanted instead of blowing a raspberry, "nya nya, you forgot [list trim] again"
(and cheers for route2 on that front).
hjh
-
@ddw_music said:
Symbols aren't "the point" of [route], but why then does [route] not automatically strip the "list" tag?
What do you mean? It does strip it... sending "list dog cat" to [route] strips (or "trims") the list selector and outputs "dog cat". Or do you mean, why doesn't it have a list method and understands that you have a list and then must route according to the first element?
Well, as to why it is as it is, I just looked at the code. I had a guess that it was just overlooked, so, a bug, a mistake. But I see now there was a clear intent to trim the list selector, and, I don't know why, it doesn't make much sense to me, I have to agree. It seems it wanted to to data type routing, as it can do [route float], and also pointer, but then it just failed with the list data type.
So as I see there were some bad design choices/mistakes, but Pd is very conservative and careful on this sense, and some real and clear bugs are documented as is, check [bendin]/[bendout].
As someone who designs lots of objects, I can see how even if we try hard, we always tend to find some mistakes and regret some choices. This is why ELSE has been on "experimental" mode for almost a decade. I just fix and change the behaviour and design, but this opposite extreme is also bad
and I will finally stop doing that when PlugData 1.0 is out, which might happen this year
and then I'll just have to live with some screw ups.
But hey, I think that ELSE fixes and deals fine with routing elements like [route], or data types, or the whole message with [routeall]
-
@ddw_music said:
but why then does [route] not automatically strip the "list" tag?
Lists were simpler things in the early days of pd with [pack] being the primary list object, there was no [list], so an object just to trim the selector would seem somewhat useless with how lists could be used and [route] doing the trim would be sensible. Quick look and [list] did not get added to pd until 0.39. Possibly a lack of foresight/planing or possibly things evolved differently than planned.
@oid That was a useless post. Good use of lists unpacking to inlets.
Can make much neater patches than [list store] and really gets you to structure your data and patch right to left which often results in a messy patch with [list store]. Interestingly both [i ] and [f ] show this behavior, which really seems useless but more than once I have found an error in a patch because of this and one of those errors which would have been difficult to spot otherwise. -
@oid said:
Lists were simpler things in the early days of pd with [pack] being the primary list object, there was no [list], so an object just to trim the selector would seem somewhat useless with how lists could be used and [route] doing the trim would be sensible. Quick look and [list] did not get added to pd until 0.39. Possibly a lack of foresight/planing or possibly things evolved differently than planned.
hmmm, I see, and yeah, I get that a lot with my library, which keeps growing and growing. And a lot of bad decisions I face is when I add more objects, or different objects, or want to add new features...
If I never added objects it would be much more stable and I wouldn't break things so much. It's hard to know before hand what you will want to do in the future
anyway, that makes sense indeed, thanks
-
I've read the updated manual back and forth but there are still some things unclear to me .
Take the following example
The message c3 f3 a3 , the first selector is c3 and thus this message is an implicit symbol , correct ?It's not a list because the list gatom does not understand it ., neither does the symbol gatom , so is it an unindentified message ?
Putting the same message through a list and the listbox understands it ( since the message starts with a symbol atom, a list must be explicitly given )
Next , the message c3,f3,a3 , three messages after each other each with a symbol identifier
Putting these through a list and we get again 3 successive messages each with a symbol identifier , the symbol gatom only understands it after list processing ( obviously only one element is shown since the message is separated )
-
@gentleclockdivider said:
The message c3 f3 a3 , the first selector is c3 and thus this message is an implicit symbol , correct ?
No, it is just a message, to be a symbol it would need the symbol selector. We have three selectors; float, symbol and list, when an object gets a message it checks for those selectors to make sure it is getting the correct type of data, if it lacks one of those selectors it treats it as a method like 'set' so your [list store] knows it should set its internal state instead of operate on the data and produce output. The alternative would be to have reserved words which you would have to escape or add a selector to, so if you wanted a [list] to store the message [set 1 2 3( you would have to do [list set 1 2 3( or [\set 1 2 3(. The pd way avoids reserved words which means we don't have memorize a long list of reserved words, just the three selectors and the mostly consistent ways they are handled.
Next , the message c3,f3,a3 , three messages after each other each with a symbol identifier
None of those have a symbol selector, those are just three messages. You can run those through a [symbol] instead of a [list] and for this sort of thing that is a good idea, explicitly states that it is a symbol so you don't have to trace the patch to figure out what is going on.
-
@oid said:
@gentleclockdivider said:
The message c3 f3 a3 , the first selector is c3 and thus this message is an implicit symbol , correct ?
No, it is just a message, to be a symbol it would need the symbol selector. We have three selectors; float, symbol and list, when an object gets a message it checks for those selectors to make sure it is getting the correct type of data, if it lacks one of those selectors it treats it as a method like 'set' so your [list store] knows it should set its internal state instead of operate on the data and produce output. The alternative would be to have reserved words which you would have to escape or add a selector to, so if you wanted a [list] to store the message [set 1 2 3( you would have to do [list set 1 2 3( or [\set 1 2 3(. The pd way avoids reserved words which means we don't have memorize a long list of reserved words, just the three selectors and the mostly consistent ways they are handled.
Next , the message c3,f3,a3 , three messages after each other each with a symbol identifier
None of those have a symbol selector, those are just three messages. You can run those through a [symbol] instead of a [list] and for this sort of thing that is a good idea, explicitly states that it is a symbol so you don't have to trace the patch to figure out what is going on.
But the manual clearly states that the first atom in a message is the selector , and for mesage c3 d3 e3 , the first atom is c3 .
Isn't c3 a symbol , it starts with the letter C ?
When the message is separated by commas , and send though a list , the console clearly shows these are seperate symbols , why then ?
To be fair , I think pure data is a million times more complex than supercollider or anything else I have worked withManual :
quoteMessages contain a selector followed by any number of arguments. The selector is a symbol that defines the message type. The arguments are anything that follows and may be symbols or numbers (aka atoms). For instance "list a b c" has a "list" selector, which defines the "list" data type, and "a b c" is the actual message. This message is only composed of symbols but a list message can combine two or more symbols and/or floats.
unquote
-
@gentleclockdivider I think that excerpt from the manual kind of gets overly technical, depends on how earlier parts of the manual handle things. Technically, everything in your patch is either a float or a symbol but selectors tell objects how they should treat it and if the object does not see a selector it recognizes it prints an error to the console. Selectors are not types, more like methods and I sort of used "selector" as type and made methods separate. The symbol selector has one argument, a symbol and each object treats the first item in a message as the selector to tell it how to deal with its arguments.
Perhaps @porres or another dev will chime in on selectors vs methods in pd, both are used in the help files, are they interchangeable? Should they be unified or distinguished better? That excerpt muddles the distinction, if there is one.
When the message is separated by commas , and send though a list , the console clearly shows these are seperate symbols , why then ?
Because those are three separate messages each being sent to [list] in order from left to right, [list] is one of the objects with no methods and applies the appropriate selector to the data it receives. Try that with an object which has methods like [list store], won't work, you will get three errors.
To be fair , I think pure data is a million times more complex than supercollider or anything else I have worked with
for years I had that same feeling about pd, spending some time in vanilla pd with no externals helped a good deal, got me over the hurdle with understanding the quirks of pd and dataflow.
-
@gentleclockdivider said:
The message c3 f3 a3 , the first selector is c3 and thus this message is an implicit symbol , correct ?
nope, there are no implicit symbols in Pd. Symbols are defines with the "symbol" selector, and can take only one argument, quote from the manual "The symbol selector can only have one symbol argument"
It's not a list because the list gatom does not understand it ., neither does the symbol gatom , so is it an unindentified message ?
nope, it is a defined message, with a defined selector
@oid said:
We have three selectors; float, symbol and list
No. that's wrong, we have "infinite" selectors. The selector is a symbol that defines the data type (as the manual says). So, any symbol that comes first in a message is the selector. There some special selectors alright, but they are not just three, but five! Another quote from the manual: These special types are: "float", "symbol", "list", "bang" and "pointer"
if it lacks one of those selectors it treats it as a method like 'set' so your [list store]
The "set" IS the selector. What you refer as a "method" is if the object understands that message selector. So it means it has a function (or "method") to deal with it. If it does not, it will say "no method for set", but it can also say "no method for symbol/float/bang", so it's the same for the special selectors as is with any other general selector. (I see you asked me to chime in later about this, well, here it is).
@gentleclockdivider said:
But the manual clearly states that the first atom in a message
is the selector , and for mesage c3 d3 e3 , the first atom is c3 .
Isn't c3 a symbol , it starts with the letter C ?Yes, it is a symbol, hence, it is the selector of the message, so "c3 d3 e3" is a message whose selector is "c3" and the actual message is "d3 e3".
When the message is separated by commas , and send though a list ,
the console clearly shows these are seperate symbols , why then ?they are separated because you're using commas, and commas separate the atoms. And if you sent it to print, you wouldn't see the symbol selector. But since you're passing them through [list] they are gaining a list selector. But since lists need to have two or more elements, one-length lists are converted to a symbol or float message (I think we discussed this on this thread already, and the help file of [list] discusses that).
Now, to be honest, I don't understand why you brought this up here, and why do you ask. I don't see the relation. Just let it be clear that you have 3 messages with just a symbol, and that these are selectors! What is the message then? No message, just selectors. The manual exemplifies something like this when it says about the "stop" message, let me quote it: "If a message contains only one symbol, like "stop", it is considered a selector with no actual message (i.e., no arguments) attached."
I guess the manual could have more examples of generic selectors maybe? I don't know what is exactly not clear in the manual, please let me know so I can see if I can improve it.
@oid said:
I think that excerpt from the manual kind of gets overly technical
Why do you say that?
it's telling it as it is...
-
I guess this subpatch that I referenced to earlier has more examples and makes things clearer? Should I bring some of this into the manual?
Anyway, thanks for checking the docs and letting me know if they can be improved
-
I think pure data is a million times more complex than supercollider
Oh, don't get me started with SuperCollider
geez, that thing is what I call a nightmare
Thee whole syntax of Pd is so damn simple, I can teach it quickly in a single class. The syntax of SuperCollider, on the other hand... damn,... what a PITA
There are really a couple of tricky things to learn about Pd's syntax, like the dollar sign deal, and how to deal with selectors, and that's it. And the deal is that the first thing (symbol) in a message sets the message type (feels simple, clear and straightforward to me), and you have some special data types. I really cannot see the complexity in here! I guess it becomes simple once it's all clear to you.
And I hope it is clear now
cheers
-
@porres Couple of things SuperCollider can do that Pd cannot:
-
Dynamically add DSP glitch-free -- this is central to my musical practice, actually, the idea that I can load up an instrument at any time and already-running audio will continue without a break. In Pd, loading a big audio file can glitch the audio so you need a workflow where everything is laid out in advance and that's just what you're working with. Understood that one of the benefits on the Pd side is a tighter timing model, but that comes at a cost of less flexible improvise-ability.
-
In SC, I implemented a live-coding dialect and I can safely say, the kinds of string manipulation that this requires are beyond the practical limits of Pd. You can convert a symbol to a list of ASCII bytes but the state-machine iteration over the source string IMO exceeds the threshold of what's practical to do in graphical patching (and that's not even mentioning regex matching, which I use extensively). It's not impossible but it would be so complex in patching that anyone who wanted to do it would be advised to just write the parser in Lua and embed into the patch. Don't even try; Pd does not have the string tools.
That second point is related to the fact that graphical patching is not at all well adapted to traditional comp-sci types of tasks. If it were better than coding, computer scientists would have adopted it. But it's (sorry) objectively clumsier at if-then-else and looping. Like, if you put a hundred Pd users in a room and asked them to make a for loop with an index, a majority wouldn't be able to (not really their fault, because nobody really teaches how to write a for loop) and of those who could, you'd get all unique solutions with varying degrees of efficiency. That's just a basic for loop. In SC, there's ".do" -- there are things I'll try to do in SC because basics like this (or recursion, or early-exit from a loop) are more straightforward; I would never, ever attempt some of those in Pd (and it's hard to express the depth of that feeling -- incidentally I did implement a classical priority heap algorithm in Pd, and that was ok because it's just a
while
, but I could have done it faster in SC -- except I wouldn't have to because SC already has a PriorityQueue).
I also think many media artists don't need all the CS stuff, and that's fine, Pd is an easier way in.
hjh
-
-
@oid said:
No, it is just a message, to be a symbol it would need the symbol selector.
Torres says:
Yes, it is a symbol, hence, it is the selector of the message, so "c3 d3 e3" is a message whose selector is "c3" and the actual message is "d3 e3".I wrote :
The message c3 f3 a3 , the first selector is c3 and thus this message is an implicit symbol , correct ?So It's not implicit but c3 is a symbol .
@toress
Why would I bring this up , because this is the topic for it , no ?
And because I am writng my note notation/ rests like this : c3---f#4---g3--- ,
edit : can't (yet ) get the multiquote to work . -
@gentleclockdivider said:
So It's not implicit but c3 is a symbol .
c3 is a symbol, the message type is not a symbol, not implicitly a symbol message type. The type of message is 'c3', the actual message is 'd3 e3', so this 'c3' message has two arguments: 'd3' and 'e3'.
I bring this up , because this is the topic
I meant I didn't understand the confusion about it.
-
@porres said:
The "set" IS the selector. What you refer as a "method" is if the object understands that message selector. So it means it has a function (or "method") to deal with it. If it does not, it will say "no method for set", but it can also say "no method for symbol/float/bang", so it's the same for the special selectors as is with any other general selector.
And that is what I was missing, the old terse documentation which I learned from made it seem like selectors were essentially types and methods had nothing to do with selectors but the reality is that any valid selector has a corresponding method, that any object which accepts the float selector also has a corresponding float method? To put it into pd terms, a [f ] is essentially this on the inside:
If I understand this correctly, what a selector actually selects is the method for its arguments? If so I think this is why section 2.4.1 comes off as overly technical to me, it never tells us what a method is and how selectors relate to methods but it and pd's help files and pd's errors assume we will just understand this relation; for many of the seasoned programmers coming to pd this is probably a safe assumption but pd attracts a wide range right down to those who have no programming experience and for them it is quite abstract. -
@porres said:
I guess this subpatch that I referenced to earlier has more examples and makes things clearer?
Well, that's in "Fig. 2.4.2 Different selectors", so I put there as well in the manual, so I wonder what is not clear about all this.
-
@oid said:
any object which accepts the float selector also has a corresponding float method?
yup, which is the function that deals with it, and float, symbol, bang, list and pointer are special methods, with predefined macros to add them, others have to be specified manually. Check the source code of any object, it'll be clear.
it never tells us what a method is and how selectors relate to methods
that section does not, and the manual doesn't say much about it other than one mere usage of the term. I agree we could have some more and I could add that... it's nice to better explain what the "no method" error is... but hey, this is not being "overly technical", on the contrary, mentioning about "method" here could be arguably an unnecessary technicality in that subsection.
-
@ddw_music I hear a lot about what SC can do that Pd can't, but that was not the discussion, far from it, as it was actually about how Pd is so much more complicated, or one might say complex, when I think it is not at all the case
and sure, SC being more complex and complicated should give people something in exchange of that steep learning curve.
Not for me though.
I don't care for live coding, for instance. I never needed scripting in Pd as well. Having said that, I'd love to be challenged in offering a "pd solution" to some of its things.
You know, I stole a lot from SuperCollider into ELSE, I'm interested.
In Pd, loading a big audio file can glitch the audio so you need a workflow where everything is laid out in advance and that's just what you're working with
This can be solved with an external, and [else/sfload] can load big files without choking Pd by having a multi-thread mechanism.
that's not even mentioning regex matching
MAX has a [regex[ object and I thought about having something like that as an external, I just never needed, but I just see that you can offer some alternatives with externals.
Don't even try; Pd does not have the string tools.
let me try, I wanna have a better idea of what you mean
if you put a hundred Pd users in a room and asked them
to make a for loop with an index, a majority wouldn't be
able to (not really their fault, because nobody really teaches
how to write a for loop)Did you really run that test though?
and well, not sure if I know what you mean, because if it's what I think, it this seems like a pretty basic lesson for Pd. It's on the control examples, I have it in my tutorial, tell people to check them
I always teach my students. It's a pretty simple operation and task. ELSE also has the [loop] object...