I’ve actually been in the position of criticizing a programming environment, rather recently… bear with me, I have a point to this 
A few months ago, it occurred to me what is the big problem with graphical patching systems (Max, Pure Data). Suppose you need an iterator over a list. In Pd, list iteration isn’t exactly hard, as long as the result is going to one place in the patch: a subpatch or abstraction encapsulates the behavior and the outlet is connected to the place where you want it to go. But… what if you need the output to go to different places at different times, as in a state machine? In SC, you simply create a stream (CollStream(list)
or Pseq(list, 1).asStream
). Anywhere in the code can call next
on the stream, and the result comes back to the caller: easy. In Pd, the result goes to one predetermined location (via patch cable). To work around it, you could either use [send] / [receive] pairs with the send target set at runtime (exposing the guts of something that is basic in text languages) or make the list and index storage global (breaking encapsulation).
So I went onto the Pd forum and started laying out the case: that there are some computational problems that are clumsy to address in patchers because of the lack of function call/return, and that this discourages users of patchers from taking on creative projects that would benefit from that, and that this limits what is conceivable in these environments (to such an extent that both Max and Pd eventually just gave up and added scripting objects).
The outcome of the discussion was basically twofold: 1. I should restructure the computation so that I don’t need call/return; 2. Because I’m “fixated” on call/return, I may be missing other strengths of patchers.
Well, I’m still convinced that no call/return is a serious limitation – but one thing I learned from that discussion is that the user base of a programming environment is a living culture that is unlikely to change radically based on one person’s input. In that sense, both of those outcomes were right about one thing: “it is what it is,” both good and bad.
Which leads to the question for this thread: What is the outcome that you would hope to get from this discussion? In my Pd thread, I had hoped they would think about it and perhaps open a feature request for Pd to implement a call/return mechanism that’s idiomatic to patchers. This didn’t happen (and tbh I didn’t really expect it to). Or, even more basically, I hoped they would admit that I was right and that the software they love is flawed. This didn’t happen either (huh, I wonder why
).
I’d just suggest again that live coding is a different beast. When you’re onstage, with a few dozen/hundred people potentially getting bored because the music isn’t changing fast enough, you do actually want the system to do something sensible with a wide range of input. For this specific example, the baseline syntax for a synth argument list is an array, [\name, value, \name2, value2]
. But the syntax for a UGen argument list using keywords, or for an event, is (name: value, name2: value2)
. When live coding under time pressure, you don’t want to have to think about which is allowed in which context.
Or, more fundamentally: there is no way to disallow [\name, value]
(it’s just an array), and method call argument lists can’t follow array syntax (because you couldn’t disambiguate symbols as values vs symbols as argument keywords). I think it’s a stretch to say that there is no reason for the language to be forgiving in this case.
Edit: On second thought, there’s a very interesting conversation to be had about the places in SC where an “argument list” appears, and the different syntaxes for these. It is indeed a rough edge. Part of the static is that Synth and Group are probably too low-level as abstractions – probably we should wrap up the concept of Synth, Event and Pbind arguments into a higher-level abstraction that gets translated differently where needed. But… another day, I’ve got other work for the afternoon.
hjh