Message 'envirPut' not understood

Hi,
I’m new here. Good day. This morning I ran into the following:
I defined a class MusicLibrary with some construction methods. The following works:

k = MusicLibrary.loadFromTraktor(Library.at(\musicLibraryPath), Library.at(\traktorLibraryPath));
~musicLibrary = k;

But, this doesn’t work:

~musicLibrary = MusicLibrary.loadFromTraktor(Library.at(\musicLibraryPath), Library.at(\traktorLibraryPath));

It produces the following error:

ERROR: Message 'envirPut' not understood.
Perhaps you misspelled 'envirKey', or meant to call 'envirPut' on another receiver?
RECEIVER:
class Key (000001CA97A544C0) {
  instance variables [19]
    name : Symbol 'Key'
    nextclass : instance of Meta_KeyClarity (000001CA97728F80, size=19, set=5)
    superclass : Symbol 'Object'
    subclasses : nil
    methods : instance of Array (000001CA97A54640, size=6, set=3)
    instVarNames : instance of SymbolArray (000001CA97A54740, size=2, set=2)
    classVarNames : nil
    iprototype : instance of Array (000001CA97A54800, size=2, set=2)
    cprototype : nil
    constNames : nil
    constValues : nil
    instanceFormat : Integer 0
    instanceFlags : Integer 0
    classIndex : Integer 1050
    classFlags : Integer 0
    maxSubclassIndex : Integer 1050
    filenameSymbol : Symbol 'C:\ProgramData\SuperCollider\Extensions\SUDJ-classes\MusicLibrary.sc'
    charPos : Integer 7260
    classVarIndex : Integer 125
}
ARGS:
Instance of MusicLibrary {    (000001CA9B98EAF8, gc=74, fmt=00, flg=00, set=02)
  instance variables [2]
    tracks : instance of Array (000001CA9A6510C0, size=3323, set=12)
    playlists : instance of Array (000001CAA0A1E340, size=159, set=8)
}
PATH: C:/Users/piert/MakingMusic/SuperCollider/SUDJ-execute/initialization1.scd
CALL STACK:
	DoesNotUnderstandError:reportError
		arg this = <instance of DoesNotUnderstandError>
	Nil:handleError
		arg this = nil
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of DoesNotUnderstandError>
	Object:throw
		arg this = <instance of DoesNotUnderstandError>
	Object:doesNotUnderstand
		arg this = <instance of Meta_Key>
		arg selector = 'envirPut'
		arg args = [*1]
	Interpreter:interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
		var code = "~musicLibrary = MusicLibrary..."
		var doc = nil
		var ideClass = <instance of Meta_ScIDE>
	Process:interpretPrintCmdLine
		arg this = <instance of Main>
^^ ERROR: Message 'envirPut' not understood.
Perhaps you misspelled 'envirKey', or meant to call 'envirPut' on another receiver?
RECEIVER: Key

Key is a class I defined. I inserted currentEnvironment.postln, just before the return statement of the method loadFromTraktor. This produced the environment as I would expect.

I understand that the interpreter converts ~hoi = 5 to ‘hoi’.envirPut(5). But for some reason instead of evaluating ‘musicLibrary’.envirPut() it tries to evaluate Key.envirPut().

The precise name of the variable is irrelevant. The same happens if I try it with ~mu instead of ~musicLibrary.

I am running Windows 11, and Supercollider 3.13.0

For the definition of the classes, please have a look at my github.

EDIT:
There is another similar issue. Running the following code works fine:

(
// load configuration
Library.addFromJSON("C:\\Users\\piert\\MakingMusic\\SuperCollider\\SUDJ-execute\\config.JSON");

// music library
k = MusicLibrary.loadFromTraktor(Library.at(\musicLibraryPath), Library.at(\traktorLibraryPath));
~musicLibrary = k;
)

But, if I save this code without the first and last brackets() as , and then run "initialization1copy.scd".loadRelative;, it produces the following error:

ERROR: Message 'add' not understood.
Perhaps you misspelled 'do', or meant to call 'add' on another receiver?
RECEIVER:
class Key (000002476AAA2500) {
  instance variables [19]
    name : Symbol 'Key'
    nextclass : instance of Meta_KeyClarity (000002476B4B9D80, size=19, set=5)
    superclass : Symbol 'Object'
    subclasses : nil
    methods : instance of Array (000002476AAA2680, size=6, set=3)
    instVarNames : instance of SymbolArray (000002476AAA2780, size=2, set=2)
    classVarNames : nil
    iprototype : instance of Array (000002476AAA2840, size=2, set=2)
    cprototype : nil
    constNames : nil
    constValues : nil
    instanceFormat : Integer 0
    instanceFlags : Integer 0
    classIndex : Integer 1050
    classFlags : Integer 0
    maxSubclassIndex : Integer 1050
    filenameSymbol : Symbol 'C:\ProgramData\SuperCollider\Extensions\SUDJ-classes\MusicLibrary.sc'
    charPos : Integer 7260
    classVarIndex : Integer 125
}
ARGS:
Instance of MusicLibrary {    (00000247795873E8, gc=D4, fmt=00, flg=00, set=02)
  instance variables [2]
    tracks : instance of Array (000002475D4D7E80, size=3323, set=12)
    playlists : instance of Array (0000024769CBEE40, size=159, set=8)
}
PATH: C:/Users/piert/MakingMusic/SuperCollider/SUDJ-execute/main.scd
CALL STACK:
	DoesNotUnderstandError:reportError
		arg this = <instance of DoesNotUnderstandError>
	Nil:handleError
		arg this = nil
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of DoesNotUnderstandError>
	Object:throw
		arg this = <instance of DoesNotUnderstandError>
	Object:doesNotUnderstand
		arg this = <instance of Meta_Key>
		arg selector = 'add'
		arg args = [*1]
	ArrayedCollection:do
		arg this = [*1]
		arg function = <instance of Function>
		var i = 0
	Collection:collectAs
		arg this = [*1]
		arg function = <instance of Function>
		arg class = <instance of Meta_Array>
		var res = [*0]
	Interpreter:interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
		var code = "	"initialization1copy.scd".l..."
		var doc = nil
		var ideClass = <instance of Meta_ScIDE>
	Process:interpretPrintCmdLine
		arg this = <instance of Main>
^^ ERROR: Message 'add' not understood.
Perhaps you misspelled 'do', or meant to call 'add' on another receiver?
RECEIVER: Key

Has anybody any thought on this?

1 Like

I too have had the first issue, I thought it was to do with waiting in thread, but could never find the issue. Good luck!

What’s in common between both error cases is that the result of loadFromTraktor is being passed to another method call.

k = isn’t a method call – it’s an interpreter opcode.

~musicLibrary = ... is a method call, which depends on the receiver being in the right place on the stack (the sclang interpreter stack).

loadRelative uses loadPaths which performs collect on an array of file paths, and collect adds the executeFile result into an array – so again, the loadFromTraktor the result is being used as an input to a method call.

The symptom – a method selector being applied to some arbitrary object that is clearly not the right one – indicates stack corruption.

One known possible cause of stack corruption is try, which you’ve used extensively in your classes. But… I had thought that try was reliable if you don’t use its return value directly.

(
x = [nil];
"%\n".postf(
	try { max(x, 1) }
);
)

^^ ERROR: Message 'postf' not understood.
RECEIVER: []

// but...
(
var result;

x = [nil];
try { result = max(x, 1) };
"%\n".postf(result);
)

nil  (posted = no error)
-> nil

That’s weird because I searched your code for try and you’re always using it as a block, not as a result-producing operator – there’s never a ^try { ... } or xyz.method(try { ... }) anywhere.

Maybe the stack corruption can still happen if try is nested up to some number of levels? A try block calls try, which calls try etc. I don’t have a reproducer for that though.

So one workaround might be to anticipate specific types of errors and use guard clauses, e.g.: if(xyz.notNil) { continue... } instead of try { xyz.doSomething }. It’s fussier but if it avoids interpreter bugs, maybe worth it. (FWIW I use protect a lot for cases where a cleanup needs to happen in case of error, but try, not very much.)

hjh

Hi JamShark and Jordan,
thanks for thinking along! For now I found a specific workaround, by just not needing this piece of code anymore. But in the future I will need it again, I will try to rewrite it in a more robust way which doesn’t rely on try so much and uses protect if still requiring a clean up.

Hi, I got rid if all the try statements. That did the job! Thanks (: