> > A node with Object data is just a node that can have attribute nodes. It doesn't really store a value so it defaults to returning itself when you ask it for its value.
> That's the point! If it doesn't really store a value, .value should be null.
A FlexSim treenode has a datatype. Previously you set the datatype with nodeadddata() and get it with getdatatype(); now you set and get the datatype with treenode.dataType.
A node with Object data doesn't really store a value; it stores a whole bunch of values within its attribute tree. Its dataType is DATATYPE_OBJECT.
When you ask an Object for its data, it returns itself because its data is accessed on itself as an Object rather than as a treenode:
treenode processor = model().find("Processor1");
return processor.as(Object).attrs.shape.value;
It doesn't have no data; it has object data. Its value isn't null; it is itself, the Object containing its data.
> 1. What is the difference in Flexscript between NULL, nullvar, and 0?
NULL and 0 are synonymous. This is the same as Win32 C++. It is defined within Visual Studio's stdlib.h:
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else /* __cplusplus */
#define NULL ((void *)0)
#endif /* __cplusplus */
#endif /* NULL */
nullvar is a special keyword that creates a Null Variant: a Variant whose type is VAR_TYPE_NULL. This is the same as initializing an empty Variant in C++ using:
Variant myVariant = Variant();
> NULL == nullvar // true
This is a bug. This should equate to false. I'll add a note to the dev list to fix this.
"" == nullvar is also erroneously returning true. It should be returning false.
nullvar == "" is correctly returning false.
> I also noticed that a string "NULL" is also used in some circumstances. What are the conditions that the "NULL" string is used instead of a NULL/nullvar value? "NULL" instead of an empty string ("")?
The string "NULL" is a string with the characters 'N', 'U', 'L', and 'L' in it. It isn't something special. You did not describe exactly the circumstances where you saw a string "NULL", but I suspect that it was written in a text field or table display to describe that the value of something was null, such as in watch variables or an array label's value, or something like that.
> 2. What's the difference between var and Variant?
var is a short for "variable". It is a type-inferred variable based on the datatype of the variable being assigned to it. It is synonymous with the C++ keyword "auto". It is not short for "Variant".
Variant is a special datatype that can store a wide variety of data: either a number, a string, a treenode, an array of variants, or null.
Variant is used in many places where the value returned could be one of those types, such as in dynamic label access and the return value of nodefunction(), executefsnode(), and user commands.
var is just to make writing code easier and faster. It is resolved at compile time based on the datatype that is being assigned to it. For example:
var myVariable = Color.red;
Object processor = model().find("Processor1");
processor.color = myVariable;
myVariable is of type Color, not Variant. The following code is identical:
Color myVariable = Color.red;
Object processor = model().find("Processor1");
processor.color = myVariable;
> 3. How to compare other variable types to an empty value?
string nullstr;
double nulldouble;
Object nullobj;
Array nullarr;
These are not null. FlexScript initializes your variables for you if you do not initialize them yourself.
The above code is the same as this:
string nullstr = "";
double nulldouble = 0.0;
Object nullobj = nullvar;
Array nullarr = [];
You need to treat them as such.
The string and double types are not nullable types. You cannot store a null pointer in a string or a double.
> Is there a single way to check for "missing" values that works across all Flexscript types?
No. You can't have "missing" values in all FlexScript types. A double is always a number. A string is always a string. An int is always a number. None of those types have "missing" values.
The comparison you should use depends on the type you are comparing with. FlexScript is strongly typed. When you are writing the code, you can know exactly what type you are working with, and compare it accordingly.
The place where this can become confusing is for the treenode datatype. You have multiple cases:
1. A treenode returned by an old global command, such as node(). The return value could be the SAFEREF node, which is a valid memory address, but it doesn't exist in the main or view trees. To check for whether the treenode is a valid reference, you need to use objectexists(). For example:
treenode fred = node("doesnotexist", model());
return fred == nullvar; // false
return fred == NULL; // false
return tonum(fred); // a non-zero number
if (fred) return 1; else return 0; // 1
if (objectexists(fred)) return 1; else return 0; // 0
This behavior is kept for backwards compatibility with legacy code written before the new Compiled FlexScript feature in FlexSim 2017.
2. A treenode returned by a new command, such as find(). The return value behaves as you would expect:
treenode fred = model().find("doesnotexist");
return fred == nullvar; // true (bug, should be false)
return fred == NULL; // true
return tonum(fred); // 0
if (fred) return 1; else return 0; // 0
if (objectexists(fred)) return 1; else return 0; // 0
3. A treenode stored in a Variant, where the treenode pointer is pointing at 0x0, returned by a command that returns a Variant or by dynamic label access:

Object processor = model().find("Processor1");
Variant fred = processor.myPointerLabel;
return fred == nullvar; // false
return fred == NULL; // true
return tonum(fred); // 0
if (fred) return 1; else return 0; // 0
if (objectexists(fred)) return 1; else return 0; // 0
4. A Variant that is nullvar, where the type of the Variant was unknown. For example, reading the .value of a node where you don't know whether the node has no data or treenode data:
treenode Tools = model().find("Tools");
Variant fred = Tools.value;
return fred == nullvar; // true
return fred == NULL; // false
return tonum(fred); // 0
if (fred) return 1; else return 0; // 0
if (objectexists(fred)) return 1; else return 0; // 0
Phil BoBo
Sr. Manager, Software Development