Var object type...?

While it'd be "nice" to know in other parts of the scripting interface - for the purposes of a script I'm working on, I'd really love to be able to determine what type of variant an Opus variable (Var object) is.

Is that something you have access to on your side (I would assume so) that you could expose as a property of the Var object? Maybe a Var.type property?

Specifically, I'm looking to distinguish between Vector and Map objects, as the other most common types can be accurately obtained in VBscript via TypeName() or VarType().

Otherwise, is there any workaround anyone can suggest for testing the object in some way that won't throw an error, in order to determine if it's a Vector or a Map?

TypeName would give the full object name if we had a type library, but unfortunately we don't (and are reluctant to make one for a few reasons).

With Vars, if they are persisted then the type details should be in the XML they're written in to, but there may not be a good way to detect the object type at runtime.

I guess the assumption has always been that Vars are used by whatever created them in the first place, so it already knows what types it is using and this hasn't been needed until now. In cases where different types might be used in different situations, it'd make sense to either indicate the type in the Var name (and check for both names) or in a second Var. That obviously requires cooperation between the things reading and writing the Var, but they're almost always the same script.

Are you working a Var manager / debugger or something similar?

Yes. Exactly... though the reason is also tied to part of what you said before as well.

I've got several scripts that rely heavily on Opus var based controls. I've had some intermittent issues that don't normally pop up, which I'd rather not always leave my scripts own debug messaging enabled all the time in order to trace. I have targeted the variables I know the scripts work with specifically in this other 'varMgr' script, but while I was at it - figured I'd otherwise wrap it into a standalone generic variable manager. There's been a few of those produced already by both aussieboykie and tbone, but they don't support the breadth of the different variable types my scripts are working with (Maps and Vectors, I haven't had a need to mess with Blobs - though if you were to consider a change in this area - I'd say for the sake of completeness such an enhancement to the Var object properties as I've proposed should work to report all var types).

Totally get the reluctance to create your own type library... and was rather hoping that if you had easy access to the objects type on your side of the interface, that you could just expose it as a Var object property. It doesn't address ALL situations like dealing with internal script vars... but in that case, what you said about knowing what type of object you're working with inside the script itself applies 100%. It's only really something that becomes a need when you're working with something external to the script, like Opus vars.

I've also considered extending one of my scripts in such a way that I might have it use dynamically generated variable names, which will be tougher for me to 'hard code' into a separate tool. That would otherwise send me down the route of using some prefix name or something to help an external tool determine what to do like (map_<variable_name>), which as a stopgap - I will probably do for MY specific purposes, but which doesn't help it serve as a generic tool.

+1

For now you could get away with a hacky attempt like this:

[code]function GetType( v ){
var u = "undefined"; if (typeof v == u) return u;
try{v.resize(v.size); if(typeof v.capacity!=u) return "do_vector";} catch(e){}
try{v.assign(DOpus.Create.StringSet()); return "do_stringset";} catch(e){}
try{v.assign(DOpus.Create.Map()); return "do_map";} catch(e){}
try{v.resize(v.size); return "do_blob";} catch(e){}
try{v.vars.count; if (typeof v.deselect!=u) return "do_command";} catch(e){}
try{v.add(0,'s'); if(typeof v.wday!=u) return "do_date";} catch(e){}
if (v instanceof String) return "string";
if (v instanceof Date) return "date";
return "wtf?!";
}

var ov = DOpus.Create.Vector();
var om = DOpus.Create.Map();
var ob = DOpus.Create.Blob();
var oc = DOpus.Create.Command();
var os = DOpus.Create.StringSet();
var od = DOpus.Create.Date();
var s = new String();
var d = new Date();

DOpus.Output("OVec: " + GetType(ov));
DOpus.Output("OMap: " + GetType(om));
DOpus.Output("OCmd: " + GetType(oc));
DOpus.Output("ODat: " + GetType(od));
DOpus.Output("OSet: " + GetType(os));
DOpus.Output("OBlb: " + GetType(ob));
DOpus.Output(" Str: " + GetType(s));
DOpus.Output(" Dat: " + GetType(d));
DOpus.Output(" ???: " + GetType(this.unknown));[/code]

Output:

OVec: do_vector OMap: do_map OCmd: do_command ODat: do_date OSet: do_stringset OBlb: do_blob Str: string Dat: date ???: undefined

Watch out, since that will modify the object it is testing in some of the cases. (Just map and stringset, I think.)

e.g.

[code]function GetType( v ){
var u = "undefined"; if (typeof v == u) return u;
try{v.resize(v.size); if(typeof v.capacity!=u) return "do_vector";} catch(e){}
try{v.assign(DOpus.Create.StringSet()); return "do_stringset";} catch(e){}
try{v.assign(DOpus.Create.Map()); return "do_map";} catch(e){}
try{v.resize(v.size); return "do_blob";} catch(e){}
try{v.vars.count; if (typeof v.deselect!=u) return "do_command";} catch(e){}
try{v.add(0,'s'); if(typeof v.wday!=u) return "do_date";} catch(e){}
if (v instanceof String) return "string";
if (v instanceof Date) return "date";
return "wtf?!";
}

var x = DOpus.Create.StringSet();
x.insert("Hello World");
DOpus.Output(x.count);
DOpus.Output("Type: " + GetType(x));
DOpus.Output(x.count);[/code]

Outputs:

1 Type: do_stringset 0

Edit: Trying to assign the object to a stringset (rather than a stringset to the object) and similar for the map would solve those two, I think.

I think this works, just swapped two things around:

function GetType( v ){ var u = "undefined"; if (typeof v == u) return u; try{v.resize(v.size); if(typeof v.capacity!=u) return "do_vector";} catch(e){} try{DOpus.Create.StringSet().assign(v); return "do_stringset";} catch(e){} try{DOpus.Create.Map().assign(v); return "do_map";} catch(e){} try{v.resize(v.size); return "do_blob";} catch(e){} try{v.vars.count; if (typeof v.deselect!=u) return "do_command";} catch(e){} try{v.add(0,'s'); if(typeof v.wday!=u) return "do_date";} catch(e){} if (v instanceof String) return "string"; if (v instanceof Date) return "date"; return "wtf?!"; }

Hi Leo, thanks for the quality assurence on that. o) I actually intended to add or copy empty objects to the one tested, to prevent moving data unnecessaryly each time. Don't know why I went with assign(), I think I was mislead by it's description a bit, since it mentions "copying" and misses out on the fact, that it fully replaces the content.

But anyway! No problem, because you gave them a merge() method, so let's just use that! Agree? o) Further input regarding this type testing clutch is welcome. We'd still prefer a clean way of doing these things of course! o)

function GetType( v ){ var u = "undefined"; if (typeof v == u) return u; try{v.resize(v.size); if(typeof v.capacity!=u) return "do_vector";} catch(e){} try{v.merge(DOpus.Create.StringSet()); return "do_stringset";} catch(e){} try{v.merge(DOpus.Create.Map()); return "do_map";} catch(e){} try{v.resize(v.size); return "do_blob";} catch(e){} try{v.vars.count; if (typeof v.deselect!=u) return "do_command";} catch(e){} try{v.add(0,'s'); if(typeof v.wday!=u) return "do_date";} catch(e){} if (v instanceof String) return "string"; if (v instanceof Date) return "date"; return "wtf?!"; }

I guess merging in an empty collection is a bit more efficient if the collection being tested is large. Makes sense.

How creative :slight_smile:. Thanks...

Not too late to rewrite my varMgr thing in JScript I suppose :open_mouth: