I noticed a recent conversation on this forum about adding properties to existing classes (How do I concate two Classes question) which raised a question in my mind about my own apps.
I had been loading a large number of folderItems (containing photos) into the app and creating a subClass from those folderitems that would add additional properties.
It dawned on me that this might be a costly process, compared to just adding the folderItem as a property of a new class.
So I tested - comparing adding several thousand folderItem subclasses to adding a new class with the the folderitem as one property.
In general the result was that adding a new class with a property for was always more than 5x faster than creating a sub-class. I suppose the answer is intuitive, and probably dependent upon the number of properties contained in the super-class. The speed of both is still impressive and may not impact all apps that much (e.g. 36k folderitems load in 38µsecs for sub-classing vs 7µsecs for adding a property) but it might be worth a consideration in speed sensitive apps.
In my folderitem case the speed of accessing the disk to create the folderitem in the first place was considerably longer than the whole subclassing effort. But there are other areas of the app where a difference might be more considerable.
I’m surprised that subclassing Folderitem actually works. All the access functions return a plain FolderItem. How do you then coerce that into your subclass. There are several classes, such as DataBase, where it simply does not work at all. Creating a wrapper class is the way to go.
Ah, I see. That’s pretty slick, actually. It does mean that you’re constructing 2 folderitems each time - one from the accessor and one when you construct your subclass. That explains part of the speed difference. But if it’s not affecting your performance, then if it ain’t broke. don’t refactor it.
Using a subclass like you’re doing will certainly make your code simpler.
No you do not end up with 2 instances, but in the process, you wind up calling the constructor twice. That was my point. Sure, the original folderitem that came from the accessor will go out of scope and not hang around. But you’re doing the constructor twice, as opposed to holding on to that instance as a property of the class. Granted, that does complicate your code a bit.
I’m used to dealing with databases and recordsets, where you can’t morph one into the other and your only/best option is a wrapper. It’s been a while since I dealt with a class I had to call the super.constructor.
Well, actually, no it doesn’t. I made an array of folderitems first then in separate routines I compared the speed of a new subClass vs a new “wrapper” class (hope that’s the right interpretation). So the access time for the folderitem array was eliminated in the calculations - and that was a huge time in comparison.
I think it is simply the size of the class super that will determine how long a new subclass will take to create, compared to just the few properties on a wrapper.
Of course, using a wrapper makes some things like handling events, or overloading, a tad more complicated and so other things might mess up the speed comparison and complexity to implement.
A couple of thing come to mind about this. First you are not calling the constructor twice, or making two objects an allowing one to self destruct. You are calling two constructors, however the first is simply calling the super constructor, nothing else.
Secondly why would you even create this Constructor, simply declaring the Super class will allow you to use the existing constructors on that Superclass. The only reason for creating the Constructor on the sub-class is to do something extra within its constructor. such as:
Public Sub Constructor(file as FolderItem)
// Calling the overridden superclass constructor.
Super.Constructor(file)
SomeNewProperty = True
End Sub
If you are not doing that then simply allow inheritance to do the work for you.
A folderitem constructor is being called twice. First, by the filesystem accessor that returns the original folderitem. Second, by the overridden constructor in the folderitem subclass. So, two folderitems are being constructed independent of each other.
With a wrapper class, the only folderitem being constructed is in the filesystem accessor.
Constructing two folderitems per pass has got to take more time than only constructing one. But the point is moot if it isn’t impacting performance.
Then you’re not measuring the affect of doing them both together, as your original test did. You’d have to include the time it took to create the array.
In both cases and access is made to the disk first. I simply removed this from the comparison since it is subclass vs. wrapper that I was interested in.
I don’t want to get hung up on Folderitem per se as it was used as a simple example - the access times for FolderItems are like x10^5 longer than the create times for either a super or wrapper. But in general I agree that making 2 folderitem classes is going to take longer than making 1 plus a wrapper.
Yes you are right in this simple example, in my actual code I am applying other things in the constructor.
If you don’t recreate the subclass constructor then you are not. That constructor is completely obsolete, as it does nothing extra. It’s an extra function call but nothing else, no extra objects are created or destroyed.
The constructor does not actually create the object. You can see there is no code in there that actually creates anything. In effect the Var / Dim creates the object and the Constructor allows you to override the contents of it. When there is a stack of constructors then each effectively passes the single object into the next constructor, returning it back up afterwards.
If you think about this it is the only way it could possibly work, otherwise you would never end up with a fully constructed single object.
Consider a class structure.
Var Obj as New B
Class A
Property Fish as Integer
Sub Constructor
Fish = 1
End Sub
Class B inherits A
Property Frog as Integer
Sub Constructor
Super.Constructor
Frog = 2
End Sub
You end up with 1 object with two properties Fish and Frog. Fish would be 1 and Frog would be 2.
Var creates the object of type B and calls the B constructor
Right, but FolderItem.Constructor(f as FolderItem) is a copy constructor. It creates a whole new object and copies the contents of the passed folderitem into it. You therefore have 2 objects, not one. That creation/copy step takes time.
OK, I can see that. It is another good reason to not create a constructor that simply calls the super constructor and does nothing else. If you don’t create this superfluous constructor then the problem goes away and you only have one duplication, which is what you asked for in the first place.
In testing it doesn’t seem to make any difference to the overall timing whether or not the “superfluous” super.constructor(file) line is included or not.
Likely the copy is only happening in the super constructor, there is certainly no copying code visible in the sub class constructor. I would think it would be only the time required to perform a function call.
There is only ever one folder item… there is no original folder item that goes out of scope if subclassing folder item behaves normally… and there no reason it should not.