A little-discussed fact about the Operator_Convert method is that it actually performs two different (but similar) conversion operations. Understanding what each of those conversion operations do will help you to better understand when to use the feature, and why it may not work in some instances.
The first type of conversion that Operator_Convert supports is a "convert-from" operation. This is where you are converting an existing class instance from its existing to into a different type. These operations look like:
Function Operator_Convert() as SomeType
When you use a convert-from operator, the compiler doesn't really have to do any work. Whenever an implicit (or explicit) conversion needs to take place, the compiler looks for the convert-from operator, and if it finds one, it calls it. The function itself already does all of the conversion work.
The second type of conversion is a "convert-to" operations. This is where you are taking some data, and creating an entirely new object implicitly, so that you can copy the data into it. These operations look like:
Sub Operator_Convert( rhs as SomeType )
When you use a convert-to operator, the compiler has a bit of work is has to do. It creates a new instance of the item it located the Operator_Convert method on, then it calls that method to complete the conversion. When it creates the new instance of the item, it does *not* call any constructors for it -- the Operator_Convert method takes the place of the constructor.
Now that you understand how the different forms of the conversion operator work, we can discuss the many different ramifications of that information.
For starters, you'll notice that constructors aren't called when doing a convert-to operation. That's simply something to be aware of -- if you're doing work in your constructor that you need to have happen, you'll have to perform that work yourself in the conversion case. This generally won't need to happen, since most constructors simply initialize things to sensible values, and conversion operations would do exactly the same thing anyways. But if you're doing some sort of declare work, it may still be necessary. For instance, let's say you were doing some sort of crazy COM work on Windows -- your Operator_Convert method had better call CoInitialize just to be on the safe side!
Another thing that is very easy to overlook with convert-to operators is the fact that they won't work for interfaces. Now that you understand how they work, that fact should be easier to understand -- there's no way for the compiler to instantiate a new instance of an interface. That means the following code can be quite confusing:
Interface SomeInterface
Sub Operator_Convert( rhs as String )
End Interface
Class SomeClass
Implements SomeInterface
Sub Operator_Convert( rhs as String )
End Sub
End Class
dim c as SomeClass = "12"
dim c1 as SomeInterface = "32"
At first blush, this code may look perfectly sensible, even though you get a compile error about c1 = "32". But the problem is: the compiler cannot create a new instance of SomeInterface, even though it is perfectly legal to do so for SomeClass. Unfortunately, current shipping versions of REALbasic have a pretty obtuse error for this case, but that should change in a future release.
The final implications I'd like to discuss are closely related. Convert-to operations have more performance overhead than convert-from operations because of the class allocation. Because of this, the compiler prefers convert-from operations to convert-to operations. The compiler searches for convert-from operators first, and if it finds any viable choices, it doesn't even bother looking for convert-to operators. Only if no convert-from operators exist does it look for convert-to operators.
Hopefully this better understanding of how conversion operators work will allow you to use them more effectively, or perhaps clear up some confusion about their behavior.
Interesting but I'd have turned the terminology around and referred to
Function Operator_Convert() as SomeType as "convert to" as in convert me to SomeType"
and
Sub Operator_Convert( rhs as SomeType ) as "convert from" as in "convert that to me FROM soemtype"
That tidbit aside it can be a real gotcha that the constructors are not called when doing the conversion especially if you expect that it will be
@Norman -- the constructors thing is a bit strange if you don't understand why. Calling constructors would add a bunch of needless overhead in the normal case, since all constructors usually do is set up initial state that's changed later. But the conversion operator generally sets up that state -- so initializing things is wasted cycles. But it's still a gotcha to watch out for!
Sure..
The conversion should probably set everything, but if you expect the constructor to do that and it's never called well you're in trouble.
I suppose you COULD call the constructor yourself in the operator_convert if you really needed it.
At least that way the user is n control of whether or not that overhead is incurred.
The conversion operator is the constructor in this case.
@Mars
Sure I get that and have run into this on my own
Not sure that the fact the conversion operator IS the constructor was clear to everyone
Some might expect that a constructor (if it existed) has been called, but it hasn't because the conversion IS the constructor as you point out