XE2: TValue is much faster now
About a year and a half ago, I reported on how slow the original implementation of TValue in Delphi 2010 was, touching off a storm of comments and various other blog posts as other Delphi community members conducted similar experiments. One thing that came out of it was a suggestion by Robert Love on how to improve performance by adding code to optimize for the most common cases.
I expanded on his idea and sent a suggested implementation to Barry Kelly. Unfortunately, it didn’t make it into XE, but it’s in XE2 now. It’s not exactly the code I suggested–a few things have changed in the way TValue works internally since D2010, and there’s at least one bugfix that I can see–but the basic idea is there. When storing values into a TValue and retrieving them again, there’s special code to set and retrieve the most common types directly, without having to go into the generic RTTI-based (much slower) conversion routines.
I reran the timing test under XE2, and the results were much better this time:
Variants: 2140
TValues: 2895
Still about 30% slower than Variants, but at least it’s not 2000% slower anymore. Thanks, Barry, and thanks to Robert too for the original suggestion!
Actually I wish they would work on the errors that still exist with TValue (wrong type inference and missing class operators) before optimizing it.
Well, the type inference issue is a compiler error, not a TValue problem. And the only error I’m aware of has to do with assigning a hard-coded literal float to a TValue and sometimes getting the wrong float type. Is that what you’re thinking of or is there more than just that?
As for missing operators, what operators could you put on TValue that aren’t already there?
There are implicit operators missing for several numeric types. For example try this:
v := Cardinal(High(Cardinal));
Writeln(v.TypeInfo.Name); // expected: Cardinal, actual: Int64
Writeln(v.ToString);
or:
v := UInt64(High(UInt64));
Writeln(v.TypeInfo.Name); // expected: UInt64, actual: Extended
Writeln(v.ToString);
And it gets worse when you use NativeInt/NativeUInt (which does not work correct even if specifying the type parameter). Even more when you change to 64-bit.
Is there a QC I can vote for it?
Yes: http://qc.embarcadero.com/wc/qcmain.aspx?d=96343
Still begs the question: If it slower and more restrictive than the solution everyone agrees is re-warmed dog-processed dog food, then why even bother keeping it in?
Variants cannot hold everything that TValue can. That makes TValue way better to work with especially when working with generics.
TValue is a true boxing type, Variant isn’t. With TValue, you put in what you want type-wise, but can only get back out what you put in. In contrast, Variant supports a much more restricted range of input types but can perform automatic conversions not normal to Delphi code on output. They perform different functions; what’s so hard to understand…?
The performance differential with Variants could be higher if Variants were to received some extra attention too.