Ok, maybe we’re tapping somewhere where we shouldn’t… but I’m designing an interface for an object that would really like to be able to access its parent environment as ~parent.
I understand that when know:true, setting ~parent in an Environment will set the parent for real:
a = Environment(parent:currentEnvironment, know: true);
a.use { ~parent = (test: \ok) };
a.test // -> ok
And so it doesn’t matter if I try to do a[\parent] = something: if know is true, put will set the parent “instance variable”, and envirGet will still not get it, while at does though.
So it looks like envirPut and envirGet are not “symmetric” in this.
Looking at the source code in LangPrimSource, envirPut calls identDictPut, which checks for know and parent and writes to a specific slot:
And prIdentDict_At also does the same. But envirGet doesn’t call it, calling instead identDict_lookup, which doesn’t check for know and “special fields” at all.
The compiler provides a shortcut syntax where ~ is a placeholder for currentEnvironment. This makes the expression ~myvariable; equivalent to currentEnvironment.at(\myvariable); and the expression ~myvariable = 888; equivalent to currentEnvironment.put(\myvariable, 888);
If this is true, then it’s a mistake in the envirGet primitive.
It isn’t clear from git history who wrote this, though. If that’s originally from James McCartney, I’d take it to be definitive. If somebody added it later, they might have assumed it should be equivalent without thoroughly testing. I.e., who knows?
thanks @jamshark70, I was actually really hoping you would give me some input on this <3
well, I might be misunderstanding, but looking at Bison, I see ~ being translated to envirGet and envirPut:
This bison code is from ‘initial revision’ 20 years ago (James McCartney committed on Sep 6, 2002). I looked at some more old JMC commits to shine some light on intentions here:
19 years ago, in this commit (replace envirGet and envirPut with primitives · supercollider/supercollider@0071e93 · GitHub) envirPut is calling identDictPut, but envirGet is still not calling prIdentDict_At. However, both prIdentDict_At and envirGet are calling the same function: arrayAtIdentityHashInPairs.
(note: there is also identDictAt but it’s unused and will disappear later on)
Fast-forward to today, that “code duplication” is gone, envirGet calls identDict_lookup. So, envirGet and prIdentDict_At are almost identical, with the first having an extra check for currentEnvironment and the latter having the extra check for know.
Even if I don’t feel too confident changing stuff at this level, I have a strong feeling for envirGet having to call prIdentDict_At. Actually, I would restore identDictAt and call it from both prIdentDict_At (which is meant to be a primitive for IdentityDictionary) and envirGet (primitive for Symbol).