Hi there,
Take the following minimal code :
Pdef(\test, Pbind(
\a, 1,
\b, Pfunc({|e|e.postln;}),
\c, Pkey(\a).trace,
)).play;
It displays as expected a infinite series of :
( 'a': 1 )
1
Then, with the above still running, try :
Pbindef(\test,
\b, Pfunc({|e|e.postln;}),
\c, Pkey(\a).trace,
);
and then inspect the Pdef with :
Pdef(\test).source.postcs;
You can see that the key order is :
PbindProxy('b', Pfunc({|e|e.postln;}), 'c', Pkey('a'), 'a', 1)
with a
at the bottom rendering an empty environment for Pfunc
and nil for Pkey(\a)
.
If this is not expected, should I file an issue ?
Can Pbindef
append rather than prepend the keys ?
Thanks for any pointers on the subject 
Since a Pbind
does have an expected order of keys stored as a SequenceableCollection
(Provided I read and understood the source code correctly) it would then be expected that Pbindef
replace keys at the exact position it was before in the Pbind
.
Opinions ? (Or just a pong? I feel so alone in this conversation
)
Also, then, in the Pbindef
, could one choose where the key(s) be inserted in the sequence of keys of the PbindProxy
?
- If key is already there in the
Pbind
→ replace at position.
- If its a new key → have some sort of mechanism to (prepend | append) with an optional argument being a \key (that could be expected to already be in the
Pbind
.
prepend()
→ add key to the top (the current behavior)
append()
→ add key to the bottom
prepend(\a)
→ add key exactly before \a
append(\a)
→ add key exactly after \a
Inb4; This is just a concept, not actual code… 
I think it’s worth filing a bug about this. I think it’s reasonable to assume that new keys given to Pbindef should override the old values and not disrupt the order, but the current logic when converting a Pdef to Pbindef is to put the new pairs first. The place to intervene would be here: supercollider/SCClassLibrary/JITLib/Patterns/Pdef.sc at develop · supercollider/supercollider · GitHub
(OTOH… in your code, why not start with Pbindef, instead of converting?)
The following doesn’t break the order, but introduces an unused pair:
(
Pdef(\test, Pbind(
\a, 1,
\b, Pfunc({|e|e.postln;}),
\c, Pkey(\a).trace,
\type, \rest
)).play;
)
// convert to Pbindef
Pbindef(\test, \dummy, 0);
Pbindef(\test,
\b, Pfunc({|e|e.postln;}),
\c, Pkey(\a).trace,
);
… and users shouldn’t have to do that.
hjh
Here’s a possible fix (though the actual JITLib maintainers may have other suggestions):
Pbindef : Pdef {
*new { arg key ... pairs;
var pat, src, newPairs, pairOrder;
pat = super.new(key);
src = pat.source;
if(pairs.isEmpty.not) {
if(src.class === PbindProxy) {
src.set(*pairs);
pat.wakeUp;
} {
if(src.isKindOf(Pbind))
{
pairOrder = pairs[0, 2..];
newPairs = pairs.asDict(class: IdentityDictionary);
pairs = src.patternpairs.copy;
pairs.pairsDo { |key, pat, i|
if(newPairs[key].notNil) {
pairs[i+1] = newPairs[key];
newPairs.removeAt(key);
pairOrder.remove(key);
}
};
pairOrder.do { |key|
pairs = pairs.add(key).add(newPairs[key]);
};
};
src = PbindProxy.new(*pairs).quant_(pat.quant);
pat.source = src
};
};
^pat
}
...
}
hjh
1 Like
Wow, thank you so much @jamshark70, it works like a charm
!
Kudos for the pairs[0, 2..]
syntax e.g.:
x = [\a, 0, \b, 1, \c, 2];
x.copySeries(0, 2)
==
x[0, 2..];
I had never seen that before.
Thank you! I think the whole thing was just backward. For me, this fixes it, could you pleae check if it does so for you?
*new { arg key ... pairs;
var pat, src, newPairs;
pat = super.new(key);
src = pat.source;
if(pairs.isEmpty.not) {
if(src.class === PbindProxy) {
src.set(*pairs);
pat.wakeUp;
} {
if(src.isKindOf(Pbind))
{
newPairs = src.patternpairs.copy;
pairs.pairsDo { |key, pat|
if(newPairs.includes(key).not) {
newPairs = newPairs.add(key);
newPairs = newPairs.add(pat);
}
}
};
src = PbindProxy.new(*newPairs).quant_(pat.quant);
pat.source = src
};
};
^pat
}
Will this version update keys that existed in the original Pbind and which are re-specified in the new pairs given to Pbindef?
hjh
Ah yes, no, that is not the case.
Much more uniformly, we can probably just write:
*new { arg key ... pairs;
var pat, src, oldPairs;
pat = super.new(key);
src = pat.source;
if(pairs.isEmpty.not) {
if(src.isKindOf(PbindProxy)) {
src.set(*pairs);
pat.wakeUp;
} {
if(src.isKindOf(Pbind)) {
src = PbindProxy(*src.patternpairs.copy).set(*pairs);
} {
src = PbindProxy(*pairs);
};
pat.source = src;
};
^pat
}
}
(updated, not fully tested)