# Find the close/ adjacent node

``````(
~adjacent = { | nactive |
var leftI=0, rightI=0;
var n=0;

while{ n <= nactive} {
if (n-1 < 0,
{leftI = nactive-1},
{leftI = n-1}
);

if(n + 1 > nactive-1,
{rightI =0},
{rightI = n+1}

);

n= n + 1;
};

[leftI, rightI];

};
)
``````

I want find the adjacent node in a graphic simulation, but for the first, I waant to write this function with integer, but It returns error. does anyone knows why?

I donât know what you are trying to do âŚ But this line is almost certainly wrong. There is no operator precidence in sc - you need to put bracket around the left hand side and right hand side of the `>` operator.

``````		if((n + 1) > (nactive-1),
{rightI = 0},
{rightI = n+1}

);
``````

It works with it thanks

Just as more of an explanation, some of which you might already know.

SuperCollider operates sequentially on expressions, turning each operation into a message call.
âŚexcept for direct message calls (using `.`) which operate on their immediate receiver.

(the following code isnât real and is just for illustration)

So `1 * 2 + 4.pow(2) * 2` is reallyâŚ

``````1.times(2).plus( 4.pow(2) ).times(2)
``````

This is very confusing and if supercollider were remade today this would be fixed as this is what is expectedâŚ

``````( 1.times(2) ).plus( 4.pow(2).times(2) )
``````

The `.` operator should happens first, then `*`, and finally `+`.

In other words, Supercollider doesnât obey the laws of BODMAS âŚ instead it does something likeâŚ Brackets, Accessor, Everything-else (BAE).

Meaning your original code did thisâŚ

``````n.add(1).greaterThan(nactive).minus(1)
``````

âŚwhich took `1` from a boolean value, when you wantedâŚ

``````( n.add(1) ).greaterThan( nactive.minus(1) )
``````

(Technically the brackets around the `n + 1` are optional)

Defining exactly what an expression is and where they occur is a little complex.
One oddity is the assignment, `=`.

This âŚ

``````b = a = 3 * 2
``````

does not reduce to this âŚ

``````b.assign(a).assign(3).times(2)
``````

That is because `=` isnât an operator but something else.

A bit off topic, but are you sure this is not whatâs intended ?

I find operations âresolvingâ from left to right, not only somehow funnier and simpler than what school taught me, but also very efficient when itâs about signal processing, i.e. when writing synthdefs. It feels like plugging effects one after an other, like I would do with my guitar. I never ask myself if I need to enclose my wah-wah pedal inside brackets to prevent it from modifying the sound before where itâs placed .

But itâs true that it take a lot of times reinserting brackets where needed inside the pure âlogicalâ part of the code, and I even put brackets around some operations that indeed are going to be calculated first, just so any reader that doesnât know how SC operates can understand directly.

I definitely donât know what was intended when supercollider was designed, but I imagine it was to speed up the parsing.

Defintily agree it makes sense when talking about signals, disagree that it should be the default. This is because its confusing as mentioned, and sometimes you donât want a sequence of operations, having more explicit ways to deal with this might be nice.

A little while ago I posted about function chaining so you can do thisâŚ

``````SinOsc.ar(...)
|> LFP.ar(_, 232)
|> SomethingElse.ar(_)
...;
``````

If the Ugen class was redesigned, this could actually be written asâŚ

``````SinOsc.ar()
.lpf(232)
.somethingElse()
...;
``````

I like to think of the `.` operator (and `|>`) as a parallel to fmap in functional languages.
Point being, these operations are exactly what you want if you need a dependant sequence of operations â this makes them great for sequential signal processing.
If you need to use some other structure, you need another tool and usually, operators are that tool.

You could imagine some supercollider-like language that preserves this behaviour but does so explicitlyâŚ

``````SinOsc.ar() .+(1) .*(2);
``````

There are also combinators, which fmap is just one ofâŚ
In my thing, I use `|>.fork` for doing things in parallel and recombining them âŚ

``````|>.fork ['++', _.reduce('+'), _.reduce('-')] // mid side conversion
``````

âŚand another is tap, meaning, do this function but return the old result â useful for IO.

``````SinOsc.ar([324, 224])
|>.fork ['++', _.reduce('+'), _.reduce('-') ]
|>.tap BufWr.ar(_, \bufNum.kr)
|> LPF.ar(_, 345)
``````
2 Likes

nice!

I have also found my way to |> and |>.tap (or equivalent!) and use them absolutely everywhereâŚ

``````Pipe_UTIL {
*getFunc {|a|
^a.isKindOf(Symbol).if(
{ {|...b| a.applyTo(*b)} },
{ a }
)
}
}

+Object {
identityFunc { ^this } // unlike _.value, this always does nothing.
^case
if(f.size < 3, {Error("|>.fork must have an array of 3 or more functions").throw});

f[1..].collect{|o| Pipe_UTIL.getFunc(o).(this) }
.reduce(Pipe_UTIL.getFunc(f[0]))
}

{adverb == \tap} { Pipe_UTIL.getFunc(f).(this); this }
}
}
+Function {
^case
{ |...a| Pipe_UTIL.getFunc(f).(this.(*a)) }
}
if(f.size < 3, {Error("|>.fork must have an array of 3 or more functions").throw});
{ |...a|
f[1..].collect{|o| Pipe_UTIL.getFunc(o).(this.(*a)) }
.reduce(Pipe_UTIL.getFunc(f[0]))
}
}
{ |...a|
var r = this.(*a);
Pipe_UTIL.getFunc(f).(r);
r
}
}
}
}

``````

So here is an exampleâŚ

``````SynthDef(\pipes, {
WhiteNoise.ar()
|>.fork ['+',
_.identityFunc,
BHiShelf.ar(_, 5000, 4) |> _.tanh
BLowShelf.ar(_, 500, 4) |> _.tanh
]
|>.tap ReplaceOut.ar(\rout.kr, _)
|> (_ * -10.dbamp) |> _.tanh
|> Out.ar(\out.kr, _)
})

SynthDef(\noPipes, {
var sig = WhiteNoise.ar();
var sig2 = sig + (BHiShelf.ar(sig, 5000, 4).tanh) + (BLowShelf.ar(sig, 500, 4).tanh);
var attenuatedSig = (sig * -10.dbamp).tanh;
ReplaceOut.ar(\rout.kr, sig2);
Out.ar(\out.kr, attenuatedSig);
})
``````

A few things to noteâŚ

It is often better to write `(_ + 1)` rather than just `+ 1` as the latter does not work when you are building a chain of Functions, but does work if you are immediately applying them.

``````f = (_ * 2) |> (_ + 1);
g = (_ * 2) |> _ + 1;
f.(1) // returns 3
g.(1) // returns a BinaryOpFunction
``````

`|>.fork` takes the combining function as its first array element, but there must be more than 2.
Internally it uses `reduce` to combine them.

When using function composition in this way, some of supecolliderâs more questionable design choices start to rear their heads.
One thing that always catches me is that `++` doesnât actually do array concatenation (I blame String for decaying into an Array) if the left hand side isnât already an array like thing (but nil works and so do, importantly, Ugens).
Here is the same midside conversion on numbers which donât turn into arrays.
`[0.2, -0.7] |>.fork ['++', _.reduce('-') |> _.asArray, _.reduce('+') |> _.asArray]`

In the past I have had many different adverbs on |>, there is a whole branch of logic call combinatory logic that deals with these sorts of operators. I think these are the only useful ones as supercollider has good functional support already â might be wrong though.

1 Like

This is an excellent habit!

In systems that allow user defined operators, and where theyâre widely used for different kinds of behaviours (math, logic, control flow, sequencing, set operations &etc.) itâs not obvious what precedence rules are nicest.

The approach of Smalltalk (and Apl and J and K) has the definite virtues of simplicity and clarity!

Fortress had nice rules giving a partial ordering, but theyâre rather complicated, as the report acknowledges (see below).

Swift has nice rules too.

The Haskell model is also very simple, but gives a total orderâŚ

While the rules of precedence are complicated, they are intended to
be both unsurprising and conservative. Note that operator precedence
in Fortress is not always transitive; for example, while + has
higher precedence than < (so you can write a + b < c without
parentheses), and < has higher precedence than â¨ (so you can write a
< b â¨ c < d without parentheses), it is not true that + has higher
precedence than â¨ â the expression a â¨ b + c is not permitted, and one
must instead write (a â¨ b) + c or a â¨ (b + c).

https://www.ccs.neu.edu/home/samth/fortress-spec.pdf
â16.2 Operator Precedence and Associativityâ, p.102

1 Like