Just a question to understand shorter forms of syntax

Dear users and developers,

The following syntax

.xxx_({ })

could be shortened as follows:

.xxx_{ }

However, the following syntax

.xxx_([ ])

couldn’t be shortened as follows:

.xxx_[ ]

For example,

w = Window();
Button(w, Rect(10, 10, 100, 100))
.states_([["press me"]]) 
// .states_[["press me"]] // <- error
.action_({ |button, val| [button, val].postln })
// .action_{ |button, val| [button, val].postln } // <- no error

Why do they differ? I just used it as it is, but I am suddenly curious about why.

These are all method call arguments. An argument list should generally be within parentheses.

The exception is: if the last arguments are all functions, then they can be written outside (after) the parentheses. This is because some methods are normally used as control structures (if, while, do, etc).

Which looks nicer?

if(condition, {
    true branch
}, {
    false branch

if(condition) {
    true branch
} {
    false branch

Functions may be placed outside argument-list parentheses to support this structure. That’s the only reason for this. There was never any move to allow every type of object to spill over outside the parentheses.

An array in brackets isn’t a function. Therefore it can’t serve as an if/while/do body, so the above doesn’t apply. It must be in parentheses.

Here is another counterexample: value_ x + 1 – is that value_(x + 1) or value_(x) + 1? Ambiguity is never a good idea in computer language syntax; hence, this confusing situation should simply be disallowed.

Also it works only for trailing functions. You can’t do fork { ... routine body... } AppClock – it must be fork({ ... routine body ... }, AppClock) or { ... routine body ... }.fork(AppClock) because a non-function argument follows a function.


1 Like

sclang is made in part for live coding, so its full of little shortcuts, stuff which can be omitted when it’s not strictly necessary and a general openness to having various ways to accomplish the same goal.

i strongly suggest not to invest time in optimizing character count. if you’re not livecoding you can write it out. Personally i would disallow/warn about most of the symbolic notation shortcuts for class code

1 Like

The Symbolic Notations help file doesn’t state it explicitly, but there are two types of symbolic elements in SC:

  • Syntactic elements, such as [ ... ] for arrays, { |argname| ... } for a function with arguments, x = abc for assignment, series notation, etc. Most of these would be impossible to disable – there is no keyword for assignment or function definition. (Technically, for arrays, you could write Array.new(3).add(1).add(2).add(3) for [1, 2, 3], but nobody would be very happy with that.)

    • Related to that are the at / put syntax shortcuts, a[1] === a.at(1), or a[1] = 2 === a.put(1, 2). Here, too, I wouldn’t see much benefit in forcing class code to be pedantic about using the method name, while interactive code would allow the [] shortcuts.
  • Symbolic binary operators, consisting of any of !@%&+-*/<=>?| (did I forget any?). For these, the simplest rule would be to allow all of them, or allow none of them – but, a + b is currently the only way to write addition, so we couldn’t disallow all of them. Then you would have to decide which binary operators are “OK” and which are not. I don’t see a way to do that other than an arbitrary list, which is likely to be a matter of individual preference more than a consistent principle. It might seem like a good idea to throw warnings in class code that uses x @ y rather than Point(x, y), but when you try to articulate why @ is bad while + is good, it’s going to get sticky in a hurry. (I’d argue that if this can’t be articulated, then it shouldn’t be enforced as a rule.)

So I end up with… not a bad motivation (as I’ve said elsewhere, over the years I’ve come to feel that it’s better to write verbose, readable code than convenient sugary code), but there’s not really a good way to enforce it. I guess it’s a matter of coding culture rather than of technology.