Where Microsoft went wrong with VARIANTs
Variants sound cool don't they? MS certainly thought they did, so they implemented them all over the system. Over time the type checking code grew and grew. People said variant types were bad and must be avoided at all costs. Around that time I switched to Javascript. Variant problems were still evident, but I never seemed to have the same amount of difficulty as in C++. Today I remembered why:
/*
* VARENUM usage key,
*
* * [V] - may appear in a VARIANT
* * [T] - may appear in a TYPEDESC
* * [P] - may appear in an OLE property set
* * [S] - may appear in a Safe Array
*
*
* VT_EMPTY [V] [P] nothing
* VT_NULL [V] [P] SQL style Null
* VT_I2 [V][T][P][S] 2 byte signed int
* VT_I4 [V][T][P][S] 4 byte signed int
* VT_R4 [V][T][P][S] 4 byte real
* VT_R8 [V][T][P][S] 8 byte real
* VT_CY [V][T][P][S] currency
* VT_DATE [V][T][P][S] date
* VT_BSTR [V][T][P][S] OLE Automation string
* VT_DISPATCH [V][T] [S] IDispatch *
* VT_ERROR [V][T][P][S] SCODE
* VT_BOOL [V][T][P][S] True=-1, False=0
* VT_VARIANT [V][T][P][S] VARIANT *
* VT_UNKNOWN [V][T] [S] IUnknown *
* VT_DECIMAL [V][T] [S] 16 byte fixed point
* VT_RECORD [V] [P][S] user defined type
* VT_I1 [V][T][P][s] signed char
* VT_UI1 [V][T][P][S] unsigned char
* VT_UI2 [V][T][P][S] unsigned short
* VT_UI4 [V][T][P][S] unsigned long
* VT_I8 [T][P] signed 64-bit int
* VT_UI8 [T][P] unsigned 64-bit int
* VT_INT [V][T][P][S] signed machine int
* VT_UINT [V][T] [S] unsigned machine int
* VT_INT_PTR [T] signed machine register size width
* VT_UINT_PTR [T] unsigned machine register size width
* VT_VOID [T] C style void
* VT_HRESULT [T] Standard return type
* VT_PTR [T] pointer type
* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)
* VT_CARRAY [T] C style array
* VT_USERDEFINED [T] user defined type
* VT_LPSTR [T][P] null terminated string
* VT_LPWSTR [T][P] wide null terminated string
* VT_FILETIME [P] FILETIME
* VT_BLOB [P] Length prefixed bytes
* VT_STREAM [P] Name of the stream follows
* VT_STORAGE [P] Name of the storage follows
* VT_STREAMED_OBJECT [P] Stream contains an object
* VT_STORED_OBJECT [P] Storage contains an object
* VT_VERSIONED_STREAM [P] Stream with a GUID version
* VT_BLOB_OBJECT [P] Blob contains an object
* VT_CF [P] Clipboard format
* VT_CLSID [P] A Class ID
* VT_VECTOR [P] simple counted array
* VT_ARRAY [V] SAFEARRAY*
* VT_BYREF [V] void* for local use
* VT_BSTR_BLOB Reserved for system use
*/
... is an extract from the headerfile describing the variant type. Javascript defines any variable as 5 things: "string", "object", "array", "number","undefined". PHP has a similar list, with subtyping on objects.
MS in their infinite wisdom decided to describe *every* dirty little secret about the object, with no easy way of seeing how to convert between them...
And then they made it worse.
Databases have their own versions of strings, dates, etc! Which f?ckmuppet thought that was a good idea huh? What was wrong with "Date" as a date?? What was wrong with number as a number? I'll tell you what: C++ programmers designed the structure.
They looked at the data they held, and described it to the letter.
Suddenly you needed to know between a 16, 32, 64, 128bit floating int used to store a date. They did this in the name of "performance". Not thinking about the amount of code every program has to run thru to clean up their mess. Now everytime you use a variant, it has to work out what it is, and turn into what it wants it to be. The advantage between 16 and 32 bit numbers from a data point of view vanish into dust, as the machine gurns every time it has to convert an I2 into an I4 (after a lengthy compare sequence). Not to mention the 16 bit number required to describe the type instantly screws up pipelines...
Stupid fools. Next time you design a datatype, make a string a string, a number a number. Then I will not have to spend hours writing code to work out what I'm being handed. Someone really should be hit over the head. Right, I'm off to try and detect nulls coming out of the Database in C++ and causing exceptions to be thrown...
/*
* VARENUM usage key,
*
* * [V] - may appear in a VARIANT
* * [T] - may appear in a TYPEDESC
* * [P] - may appear in an OLE property set
* * [S] - may appear in a Safe Array
*
*
* VT_EMPTY [V] [P] nothing
* VT_NULL [V] [P] SQL style Null
* VT_I2 [V][T][P][S] 2 byte signed int
* VT_I4 [V][T][P][S] 4 byte signed int
* VT_R4 [V][T][P][S] 4 byte real
* VT_R8 [V][T][P][S] 8 byte real
* VT_CY [V][T][P][S] currency
* VT_DATE [V][T][P][S] date
* VT_BSTR [V][T][P][S] OLE Automation string
* VT_DISPATCH [V][T] [S] IDispatch *
* VT_ERROR [V][T][P][S] SCODE
* VT_BOOL [V][T][P][S] True=-1, False=0
* VT_VARIANT [V][T][P][S] VARIANT *
* VT_UNKNOWN [V][T] [S] IUnknown *
* VT_DECIMAL [V][T] [S] 16 byte fixed point
* VT_RECORD [V] [P][S] user defined type
* VT_I1 [V][T][P][s] signed char
* VT_UI1 [V][T][P][S] unsigned char
* VT_UI2 [V][T][P][S] unsigned short
* VT_UI4 [V][T][P][S] unsigned long
* VT_I8 [T][P] signed 64-bit int
* VT_UI8 [T][P] unsigned 64-bit int
* VT_INT [V][T][P][S] signed machine int
* VT_UINT [V][T] [S] unsigned machine int
* VT_INT_PTR [T] signed machine register size width
* VT_UINT_PTR [T] unsigned machine register size width
* VT_VOID [T] C style void
* VT_HRESULT [T] Standard return type
* VT_PTR [T] pointer type
* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)
* VT_CARRAY [T] C style array
* VT_USERDEFINED [T] user defined type
* VT_LPSTR [T][P] null terminated string
* VT_LPWSTR [T][P] wide null terminated string
* VT_FILETIME [P] FILETIME
* VT_BLOB [P] Length prefixed bytes
* VT_STREAM [P] Name of the stream follows
* VT_STORAGE [P] Name of the storage follows
* VT_STREAMED_OBJECT [P] Stream contains an object
* VT_STORED_OBJECT [P] Storage contains an object
* VT_VERSIONED_STREAM [P] Stream with a GUID version
* VT_BLOB_OBJECT [P] Blob contains an object
* VT_CF [P] Clipboard format
* VT_CLSID [P] A Class ID
* VT_VECTOR [P] simple counted array
* VT_ARRAY [V] SAFEARRAY*
* VT_BYREF [V] void* for local use
* VT_BSTR_BLOB Reserved for system use
*/
... is an extract from the headerfile describing the variant type. Javascript defines any variable as 5 things: "string", "object", "array", "number","undefined". PHP has a similar list, with subtyping on objects.
MS in their infinite wisdom decided to describe *every* dirty little secret about the object, with no easy way of seeing how to convert between them...
And then they made it worse.
Databases have their own versions of strings, dates, etc! Which f?ckmuppet thought that was a good idea huh? What was wrong with "Date" as a date?? What was wrong with number as a number? I'll tell you what: C++ programmers designed the structure.
They looked at the data they held, and described it to the letter.
Suddenly you needed to know between a 16, 32, 64, 128bit floating int used to store a date. They did this in the name of "performance". Not thinking about the amount of code every program has to run thru to clean up their mess. Now everytime you use a variant, it has to work out what it is, and turn into what it wants it to be. The advantage between 16 and 32 bit numbers from a data point of view vanish into dust, as the machine gurns every time it has to convert an I2 into an I4 (after a lengthy compare sequence). Not to mention the 16 bit number required to describe the type instantly screws up pipelines...
Stupid fools. Next time you design a datatype, make a string a string, a number a number. Then I will not have to spend hours writing code to work out what I'm being handed. Someone really should be hit over the head. Right, I'm off to try and detect nulls coming out of the Database in C++ and causing exceptions to be thrown...
Comments
"JavaScript 2.0 - Jun 4, 2003
Added semantics for the library classes Object, Void, Null, Boolean, GeneralNumber (except for number formatting), Number, float, sbyte, byte, short, ushort, int, uint, long, ulong, Character, String (except for regular expressions), and Namespace."
http://www.mozilla.org/js/language/js20/
I didn't do the work, but I think we use this to convert arbitrary types from the database into the "string" which is all we want.
http://msdn.microsoft.com/library/en-us/vclib/html/vclrfcdynamicstringaccessor.asp. The code is in "atldbcli.h" so you can always copy/paste/hack.