If you access a variable by index which does not exist, DO will not throw an error, additionally if you read the .persist property afterwards, it seems to create the variable. The Exists() method suddenly returns true even though the variable has not been set explicitly. Is this the way it should work?
Ok, so you do not expect this code to "blow" at line #3 already. You hopefully don't mind if I ask why not? o)
Notice: The error below is for line #5. Thank you! o)
Line 3 of those returns a Var object. (It may not contain a value yet, and may have just been automatically created by using a variable name that did not exist yet.)
Line 5 returns the value inside a Var object.
They do different things, and until the Var has a value, the explicit Get call will fail.
If line 3 triggered an error, you would not be able to do this:
Ah ok, now I get what's behind these two. The documentation btw. says: "Get()" is an alternative to indexing the collection, which then is not entirely true if "Get()" only returns the value, not the object. At least this all explains why I get different behaviour when using "Get()" or the collection directly, thanks! o)
Knowing this now, new questions arise:
It seems, it is not yet created by just reading DOpus.vars("NotExistingVariable"), because Exists() returns "false" right after.
But what about these right after getting a non-existent variable:
var MyVar = DOpus.vars("NotExistingVariable")
accessing MyVar.value throws exception "Object doesn't support property or method" (huh?).
accessing MyVar.persist returns "false" (ok) and creates the variable (not expected). Exists() returns true afterwards.
Every property has a different reaction when accessed. I think that's quite confusing and probably not the way you wanted it to work?
If I get some type of null/intermediate object, by indexing the collection for a non-existing variable, I'd expect all of it's propertys to exist, even if they're not set to a value yet, so right now we have at least two different "var"-objects, which is quite unusual in the scripting/object-based land.
Additionally I would not expect, that accessing a specific property (.persist), leads to creation of the variable, while for accessing others properties (.name) this does not happen.
Maybe simply returning null/undefined or throwing an exception when indexing a non-existent variable is the cure for this, provided I did not overlook something and you agree to some extend, that there's something not working as intended.
Making sure every property exists on the "non-existent" variable object and also making sure that accessing any of its properties leads to creation, is another way to get consistency I assume.
The Var object can exist before the variable it represents officially exists. That is to let you create the variable in the first place.
I'm not sure time is best spent for either of us by delving into semantic trivia here. Just use what's there, as it works now. There are usually reasons for things working differently to what you might expect, often as side-effects of the scripting language or COM itself. None of them change the reality of what is there, and relying on such details is not a good idea anyway. If you want to check if a variable exists, use the method for checking if a variable exists.
My advice for handling variables:
Before getting a variable object by its index/name from a collection, definitely make sure it Exists()!
If the variable does not exist yet, the returned variable object will be broken and lead to unexpected results while making use of it - its properties.
I'm fine with that, just not with the fact, that this var object is different to regular ones, because you run into problems, if you don't know about it.
I don't think this is sematic trivia, as long as malfunctioning objects are undocumented and as long as there's no recommendation available on how to avoid errors with them. There may be some errors left in DO as well, so I don't see a point in trying to satisify me with "reasons for things working differently".
Also please mind: This was written because I had trouble using variables, not just because I felt like bugging you.
What is malfunctioning here? If your script does something that doesn't make sense in the first place, the result doesn't seem to matter much.
Why would you call Persist on a Var you'd never set? (Except to persist that it exists with some default value you couldn't care about, maybe, which could be why it works as variables work like that in non-script commands.)
You get an object which has a valid .name property, but the .value property is missing completly.
"Half an object" so to say! Which is against all rules (I know). A null-object with an empty value, a returnvalue of null/undefined or a raised exception is very more common. If you index into a Vector or Map with non-existing keys, you get an exception too. Arguing that using DOpus.vars() directly offers creation of new variables, is surely meant to be nice, but also breaks the pattern DO uses. We have NewCommand(), NewVector() etc. to create new objects, why not stick to that and have NewVar() as well to eliminate that possible tripping point simultaneously (in the future maybe of course o).
I disagree, scripting shall be easy even for inexperienced people, what helps here is sticking to common patterns and rules. I doubt that it's easy for many people to realize that they deal with cut by half objects in specific conditions, so the results when making mistakes do matter pretty much.
That's my developers and users point of view. Whatever you take it for, please consider making things clearer in the documentation at least, as knowing is half the battle.
I would've expected using .value and Get returning undefined/null for variables that aren't defined rather than throwing that error.
It can be checked whether it is undefined or a value by using .Exists. I assume that you'd encounter it more often as an undefined variable
than as a value. This way you'd also avoid the need to wrap every var with .Exists as you'd only need to check for existence when
the value is null/undefined because anything else would indicate an existing variable.
I've barely touched vars myself, but this is how I see it.
Considering there's apparently a significant difference between .Get and .vars("NotExistingVariable") the docs should probably say so.