Accessing parameter reference outside the function call
-
In the latest build(ish) I'm getting this error in the following code:
Interface:! settingsspace.js (64): Accessing parameter reference outside the function call
inline function onPitchWheelAmountControl(component, value) { pos = thePitchWheelAmountControls.indexOf(component); thePitchWheelModulators[pos].setIntensity(value*-1); if (Content.getComponent("PitchWheelLock").getValue() == 1) { for(setdx= 0; setdx< TOTAL_NUM_VOICES; setdx++) { thePitchWheelAmountControls[setdx].setValue(value); //<-- this line! thePitchWheelAmountControls[setdx].changed(); } } }
I cant see why I cant refer to an array of controls in this way....and if I cant then a lot of things are going to be broken....any ideas?
-
Where is
pos
declared?Probably best not to use
Content.getComponent()
inline, create a reference to the component inon init
instead.Why
setdx
and noti
?I'm not sure what it means by
parameter reference
in this context, is it referring tovalue
? If so, do you have an extra curly brace floating around that is causing it to think that you're usingvalue
outside of the function? -
@d-healey said in Accessing parameter reference outside the function call:
Where is
pos
declared?-- its declared as a utility index holder...and used everywhere...
Probably best not to use
Content.getComponent()
inline, create a reference to the component inon init
instead.Why
setdx
and noti
?er, cant remember - thats not the problem tho is it...
I'm not sure what it means by
parameter reference
in this context, is it referring tovalue
? If so, do you have an extra curly brace floating around that is causing it to think that you're usingvalue
outside of the function? -
@Lindon we have some BIG problems with teh latest buid I think;
this crashes HISE when you touch a control:
const PWLock = Content.getComponent("PitchWheelLock"); var vlockValue; inline function onPitchWheelAmountControl(component, value) { pos = thePitchWheelAmountControls.indexOf(component); vlockValue = value; thePitchWheelModulators[pos].setIntensity(value*-1); if (PWLock.getValue() == 1) { for(setdx= 0; setdx< TOTAL_NUM_VOICES; setdx++) { thePitchWheelAmountControls[setdx].setValue(vlockValue); thePitchWheelAmountControls[setdx].changed(); } } }
-
@Lindon and as soon as you take out the assignment it works again;
const PWLock = Content.getComponent("PitchWheelLock"); var vlockValue; inline function onPitchWheelAmountControl(component, value) { pos = thePitchWheelAmountControls.indexOf(component); thePitchWheelModulators[pos].setIntensity(value*-1); if (PWLock.getValue() == 1) { for(setdx= 0; setdx< TOTAL_NUM_VOICES; setdx++) { thePitchWheelAmountControls[setdx].setValue(value); thePitchWheelAmountControls[setdx].changed(); } } }
Just to be clear the original code at top works perfectly in earlier builds of HISE.
-
Does it also fix it if you add a continue statement for the current slider in the loop:
if(thePitchWheelAmountControls[setdx] == component) continue;
-
nope that makes no difference.
-
@Christoph-Hart this works tho...its a hack but :
const PWLock = Content.getComponent("PitchWheelLock"); inline function onPitchWheelAmountControl(component, value) { pos = thePitchWheelAmountControls.indexOf(component); thePitchWheelModulators[pos].setIntensity(value*-1); if (PWLock.getValue() == 1) { for(i= 0; i< TOTAL_NUM_VOICES; i++) { if(thePitchWheelAmountControls[i] == component) continue; thePitchWheelAmountControls[i].setValue(value); //thePitchWheelAmountControls[i].changed(); thePitchWheelModulators[i].setIntensity(value*-1); }; }; };
-
@Lindon OK, I've investigated it a bit and actually the current behaviour is "correct" in the sense that inline functions do not allow recursion (and recursive function calls are almost always a bad idea, unless you write compilers or other abstract mechanisms).
There are some limitations for the usage of inline functions:
- no constructor (if your function definition is a prototype)
- no recursion
The reason for this rule is that a inline function cannot allocate a scope so it can be used in a realtime context, however calling a function recursively without having it's own "dynamic" scope is a recipe for disaster because it can overwrite any local values including loop indexes and so on.
In your example the recursion is hidden behind the call to
changed
which itself causesonPitchWheelAmountControl
to be executed with the first component inthePitchWheelAmountControls
. This setspos
to zero and will cause the loop to run again, this time with another index, so my failsafe continue statement will not work and the only thing that will break the cycle is indeed commenting out thechanged()
call to prevent the recursion happening in the first place.I'm not sure what made this code run in the past and why it isn't working now. One thing could be the redesign of the scope of local variables to not leak into the global namespace and made the anonymous variable definition in for statements use the local storage type. This is a good thing as this was messing with the outer function index if you call a inline function in a loop and have the outer loop index also named
i
like any sane programmer does.inline function inner() { for(i = 0; i < 100; i++) { Console.print(i); } } // some 2000 lines later inline function outerFunction() { for(i = 0; i < 5; i++) inner(); }
I've added a recursion check that tries to analyse the stack trace and throws an error message so that at least it won't crash HISE but you definitely have to rework the way you handled this callback (just call
setIntensity()
for each modulator in the loop instead ofchanged()
, this is the only thing you're doing besides causing the apocalyptic recursion machine. -
@Christoph-Hart yep - understood. I would normally never do this sort of thing, I was (however) under the impression that the UI control callbacks had a mechanism to stop this happening - I have no idea where I got this idea from -- early documentation?? My dumb mis-read ...as you say in this (and all subsequent ) situations like this I will execute the "actual" processes I want to see happen - rather than using the convenience of calling .changed() on sibling controls...
-
To be honest I vaguely remember that I've already added a recursion check specifically to the
changed
call but that is like 5-6 years ago.I would normally never do this sort of thing
I understand, a friend of yours wrote that code, classic Lindon :)
-
@Christoph-Hart said in Accessing parameter reference outside the function call:
To be honest I vaguely remember that I've already added a recursion check specifically to the
changed
call but that is like 5-6 years ago.I would normally never do this sort of thing
I understand, a friend of yours wrote that code, classic Lindon :)
"Friend"? wot you think I have friends?.... I just have t-shirts.
-
I remember the recursion check too and relied on it for some stuff, sure I mentioned it in a video.
-
I just did a test and this problem was introduced in the last few days with all the faust commits, prior to that there was no issue because of HISE's recursion protection. A build from October 8th works.
Apparently some guy called Christoph was going to introduce a stack based way of handling this to make it more robust ;) https://forum.hise.audio/topic/797/panel-changed-recursion/3
-
Can you make an example snippet that works on October 8th?
-
HiseSnippet 1090.3oc0WssaiSDFdbR8plvwE1G.q8prhkJ6cKEPqVUSyATfdHhjsKRbwxjwiSFkwyXrGWZDZk3MfK4VdT3QYEOAbCWC+isisCMMsMpKG7EQY9OMe+msGDIIz3XYDxnwn4gTjwaZNbtPMs8TLSf52QS374pDkLhg4nClGhiiodHCi5etVBiFagRe988O.ywBBsjDBcpjQnGxBXpRpCb+RFm2C6QGwBpH8tt8IRQaIWl.notoMJDSlgmPOFqEqlIx3Nc8X.PFpvJZLxXqCjdyGNU98hL4OkEyFyo5CNngfgxH2Sx8zHVSE0dJi6MXgWGi.qLnLFTOKFbOyiXdrB5kwh2MkgUoFUiGF0VFd0WBdNUgmcE3sBHYTARakAo6ZNjDwBUkbz34ML6KTzHeLD1qBkLYQ07qY1VBRHT6DfmQ6EAGJzn0d11OzB94AOoYSHzGqrNCGYMSL115oVKzaBU0VFDJEvgV2Wy79Z4YBNSPs7SDDESJrjBMKsRQRdKxBMdHXRdB8AM+glM.Ab1IlpNUSoUF8mjSlLEKlP8ZADdIX80c4ZSjeOswb9XnHo0R29EbGm04NNWt63bUti8pcG6qs63rF2woh6j8TAcGKUzSDsRARyW1z5uyx2ek7xMImFsR15Fxn0oXKQRvXZT0vfVPnJc4ReyKuzuZmIIKtTQPonufoNIjJtr9UTdvDZSpkiJPTUZSxam2jLjy7nQHFzKbGScBAkh27YM+R3S+s8QWWccVgtOqeGrBqaTyAC.vPZjho8ciNzyfodYssML6PimojgonMO0CV9pv64EyE+0wtyKOvcCXddb5.YLSmZJGe9p8UzyUKFobsuJmJW02FeSuJHAcwQUvPRoWBGqVdxodcQNCs0pNtRORR.2x7pqSd8LN8cxvno4g8NIGXv+rJPryUCrdQzuKgJHUHtsqdeV+xXj6O49b7YTeYTPdgPg5GRm.WTUJinP1B15Rpt5bXfTplxDSVdK48bOTJC6Jvfq6U0HClhi088v3jkLCX1QxivwvP+1bIYVUlsShUxfE.McG6PEMLs313aL2a2cfG+OP+6m1F94wmb6bFcCxsNqO2V6ZV+89oo4h7oNg+uUIXiBXBuKQ4D4TX9dYufQI0qQ83yhoivovnLy1WbFLOpZEBBUZziSmhWv6GetaV01xkZL2NTebBOaCWNc2l+bW2aszG5Fk8JZ79eS16Q+GK68p+X6u3e9r2cMGvTjoqd3esUDUPnasbG5huc+aY102mRTk.bKyde8qmWkG8UxDELD+HrJhAaZMgj2P3CbHT31EBJW+xRF0z42ry15yoCtoBuzC+I7jyzQe1HmoyBln.LIR9BRVAhtdc6TJ.lDoe5TCyizmsJdUFSS6crQv5c1KHDs6+gvh7Uqyi1.cd7FnytafNezFnydafNe7FnymrVcziI9L3apCxZG.BC5ls00nX0tQczeAG5GLiB
-
@d-healey Hmm, I see so the trivial example you've posted was catched by the existing recursion protection whose existence I forgot, but the example of Lindon's "friend" found a nasty way to bypass that protection somehow so I needed to pull out more heavier weapons which now break every recursive
changed()
call.So I would recommend to remove the new error message for now and then spent an evening with a glass of red wine and the poster child of beautiful code that is Lindon's snippet to find a better solution.
-
@Christoph-Hart Sounds like a good evening :)
-
@Christoph-Hart my work here is done...or more correctly my "friend's work"