VB6 Question

Silk

Well-Known Member
Disclaimer: Yes it's bad design, no I did not design it and if I were to design it, it'd be database driven.

I have a class that has literally hundreds of properties.

I have an app that needs to compare instances of this class. One or more properties may be different when comapring class A to class B, and they need flagging up if they are. Every single property is looped around and differences are flagged.

But for the best part in this app, there are no differences at all so the loop was needless work.

The classes being compared are different in such that they reference different areas of memory, that is, this test returns false:

ClassA is ClassB

.. That's because for the purpose of my test, they are actually copies of each other, i.e. I've got a Copy method which literally makes a new version of the class with the same contents in every property. As far as VB is concerned, they are different, but as far as a human is concerned, they are the same.

So I'm wondering if there's some quick way of making VB understand that they contain the same information rather than me having to loop around and check each property; as it turns out this is very time consuming (especially when some of the properties have loops to do summing.. sigh). Or if there's some clever way of snapshotting the entire contents of a class to a string/stream and doing a straight comparison there.

Any thoughts?
 
E

elDiablo

Guest
Please note I have no idea if you can do this in VB, but general coding possibilities are following.

Add a CRC to the class that computes a hash of some sorts of all of it's properties, so that when you come to check class A vs class B, you can do an initial check on the CRC to see if you need to check the properties or if you can quickly return (as you said for the most part they are the same). Obviously this means that every time you change a property, you will have to recompute the CRC. Though CRCs should be very quick to compute if you just do something like an integer that is the addition of all properties, for example.

To speed this up, you could split the properties into sections, and have a CRC for each section, so by making the CRC update quicker at a slight cost of checking CRCs (though checking, say, 5 CRCs vs 100 properties is still a big boost).

Other than that, I could tell you ways (horrible, disgusting ways) in C/C++ to do it...
 

Zooggy

Junior Administrator
Staff member
Hoy, :)

If you're really still stuck with VB6, your best bet is to go the elD route: write a simple C function that accepts two Variant type arguments and compares their contents, stick that in a DLL, Declare it in your VB project and go to town.

He says that's horrible and disgusting, but I think that's a tad much. It's vaguely unsettling, at the most... ;)

It does require you to be at least familiar with C and the Win32 API, though.

Other than that, you're stuck with the slow molasses property-by-property comparison...

(Unless you can control all the pieces of code where that class is used, in which case, I suppose you could go with the CRC redesign... but if that's the case, you might as well go with a DB redesign, like you said... :))

Cheers,
J.
 
E

elDiablo

Guest
...He says that's horrible and disgusting, but I think that's a tad much. It's vaguely unsettling, at the most... ;)...

By horrid C/C++ type things, I meant more the route of casting the objects are void*s and then going to home with crazy bitwise operations that change code from readable to "huh... that's a lot of non-alphanumeric characters...".

But yeah, you know, whatever....
 

Zooggy

Junior Administrator
Staff member
Hoy, :)

I meant more the route of casting the objects are void*s and then going to home with crazy bitwise operations that change code from readable to "huh... that's a lot of non-alphanumeric characters...".

Well, yes, that's pretty much what you have to do to implement said C function, so, yeah, that's what I thought you meant... :D

Cheers,
J.
 

Ronin Storm

Administrator
Staff member
Slightly different approach to others...

I am assuming that each property is effectively fetching/recalculating on each call then throwing the result away. What if you kept that result in a local private variable? Then you could add one method to the class that read all the private variables (which would be the last value fetched) and then use the results of that to compare instances.

e.g. (written in C# pseudo code, but principle stands)

BEFORE:

Code:
public string MyString
{
get { return this.ReadExternalString(); }
}

AFTER:

Code:
private string myString = null;

public string MyString
{
get
{
this.myString = this.ReadExternalString();
return this.myString;
}
}

public string GetComparisonData()
{
return this.myString;
}

In a way, this is building a CRC verifier but the change is easier to understand from a maintenance coder's point of view.
 

Wol

In Cryo Sleep
But for the best part in this app, there are no differences at all so the loop was needless work.

I wouldn't say "needless" was the right term.

thats like saying "if( a == 54)" is needless if a does in fact equal 54. If you need to test if class1.a = class2.a, class1.b = class2.b, and so forth, then so be it. If you want to make sure theyre equal then you *need* to do all those comparisons.

To be honest, whichever way you do it, if you want to compare more than 4 bytes (or 8 bytes on a 64bit system), you'll have to have a loop or some form of repeated code *somewhere*.

The methods of writing DLLs, trying to get this working in VB and passing classes between that is a bit overengineering a solution, and whichever way, you're going to have a loop in that DLL.

What's wrong with doing:

Public Override Function Equals(ByVal myclass As MyClass) As Boolean
Return myclass.a = a And myclass.b = b And .....
End Function

and putting each of the properties in there?

e2a: calculating lots of stuff on a property read is a bit nasty. try and cache that where possible.
 

VibroAxe

Junior Administrator
I think you can possibly do some sneakies using memory management / union.

Create a union which takes the memory space for the class and lets you access it as an array of longs.
Loop of the array of longs and subtract a.long from b.long
If answers != then return false

Note: this code might need some tinkering if you're using strings...

Some pseudo code..

Code:
public class myClass {
int property1;
int property2;
bool property3;
long property4;
float f1;
float f2;
}

typedef union {
myClass classAccess;
long[size(myClass/4)] longAccess;
} myUnion

bool isEqual (myClass A, myClass B) {
myUnion uA, uB;
uA.classAccess = A;
uB.classAccess = B;
for (int i=0; i++; i<size(myClass)/4) {
   if (uA.longs[i] - uB.longs[i] != 0) return false;
}
return true;
}

you could also do this with pointers and directly accessing the memory to achieve the same thing but being a c# man i'm less sure on pointer casting these days
 

VibroAxe

Junior Administrator
Are you able to pass by reference instead of by value?

If i've understood this correctly, it's the value comparrison we're aiming for here.

Incidentally C# has a handy .IsEqual() defined for most classes which does this for you. Don't know if it works in VB and how it works on custom classes if not overwritten
 

Zooggy

Junior Administrator
Staff member
Hey, :)

C# has a handy .IsEqual() defined for most classes which does this for you. Don't know if it works in VB

Alas, that's a .NET CLR feature. You can get it in VB.NET, but there's no such thing in VB6... :/

Also, VB6 doesn't have UNIONs. For that sort of work, you have to go to a low level language like C, but then, you're better off comparing memory anyway...

Cheers,
J.
 

Silk

Well-Known Member
I wouldn't say "needless" was the right term.

thats like saying "if( a == 54)" is needless if a does in fact equal 54. If you need to test if class1.a = class2.a, class1.b = class2.b, and so forth, then so be it. If you want to make sure theyre equal then you *need* to do all those comparisons.

To be honest, whichever way you do it, if you want to compare more than 4 bytes (or 8 bytes on a 64bit system), you'll have to have a loop or some form of repeated code *somewhere*.

The methods of writing DLLs, trying to get this working in VB and passing classes between that is a bit overengineering a solution, and whichever way, you're going to have a loop in that DLL.

What's wrong with doing:

Public Override Function Equals(ByVal myclass As MyClass) As Boolean
Return myclass.a = a And myclass.b = b And .....
End Function

and putting each of the properties in there?

e2a: calculating lots of stuff on a property read is a bit nasty. try and cache that where possible.

It's needless if you're wasting 20-30s of processing time when 9 times out of 10 the contents will match. I'm not saying those checks don't need doing, I'm really wondering if there's a faster way than comparing each proeprty.

But after some thought there isn't and there never will be. There's countless permutations on how to write the code (such as your sample) but tbh it's already written in a pretty decent way in such that I don't have to manually code each property name, rather I assign them an ID, loop around all IDs, and fetch property by ID.

I wasn't asking what's the best way to code a check on properties, rather, is it needed, can't you somehow compare the raw dump of data in each class (apart from class ID / referenced area of memory) should "match".

Then after more thought I realised it's not logically possible anyway, as a few of the properties don't return direct values (variables in the class) but instead do summing, or some other algorithms, or even branch to a child/parent class.

Thanks for the thoughts and ideas, but I'm thinking the only way to make this app fast is to re-write it to use a database rather than flat files and classes. Which maybe one day I'll be given the opportunity to do. :)
 

BiG D

Administrator
Staff member
It's needless if you're wasting 20-30s of processing time when 9 times out of 10 the contents will match. I'm not saying those checks don't need doing, I'm really wondering if there's a faster way than comparing each proeprty.

Even if there is a one-line solution, VB is still going to need to compare all those properties itself in the background.

Best bet would be to implement a hash property that is updated whenever one of the other properties is changed (as elD suggested.)

Otherwise, if you're really really concerned about performance, you could unroll the loop to save a few cycles...
 
Top