The "opCast" overloading?

Georg Wrede georg.wrede at nospam.org
Thu Nov 23 03:00:34 PST 2006


Unknown W. Brackets wrote:
>> "Arlen Albert Keshabyan" <arlen.albert at gmail.com> wrote in message 
>> news:ejvjgp$2hgk$1 at digitaldaemon.com...
>>
>>> Hello Walter!
>>> The D language is just a miracle. Sure, you already know about that :).
>>> I know the problem of "opCast" cannot be overloaded so far. But I'm 
>>> sure there
>>> must be a way to do that somehow. That's the question of a semantic. 
>>> Right?
>>> May we hope it's going to happen soon? I'm asking you the question 
>>> because
>>> you're the Father of D.
>>
>> Many people have suggested it, by i.e.
>>
>> void opCast(out int x)
>> {
>>     // put the cast result in x rather than returning it
>> }
>>
>> Which would allow for overloading by type, but also has the 
>> disadvantage that you wouldn't be able to use cast(int)Object as a 
>> temporary.  :S
>>
>> Frankly, I don't see the need for it.  D isn't trying to be C++, where 
>> you can define types which are just as "integrated" into the language 
>> as the standard types.  You can't have opAssign, or opDeref or 
>> opAddressOf, and so the "boundary" that D classes would have to cross 
>> to get to the kind of integration of C++ classes is so large, that 
>> allowing overloading of opCast just doesn't seem like it'd do much.  
>> (And to tell you the truth, I wouldn't really want to see it either!)
>>
>> The convention in D is instead to have "toType" methods which take the 
>> place of a cast.  I.e. toString, toInt, toOtherClassType etc.
>
 > I think the problem with that is simply:
 >
 > class C
 > {
 >     void opCast(out long l);
 >     void opCast(out int i);
 > }
 >
 > C c = new C();
 > short s = cast(short) c;
 >
 > What happens?  I would personally say, an error.  But someone will
 > always be mad about that.

Thinking more broadly about this,

there are two kinds of cast situations, implicit casts (those that are 
not written in the source code) and explicit casts. If we look at them 
separately for a while, it might give some insight.

Explicit casts of classes,

like the class C example above, raise some questions. Usually, when a 
cast is required, say from int to real, the result is outside of the 
realm of the castee. In other words, precisely because the int here has 
no notion of exponents or fractions we need to do the cast. Following 
this thought, one might ask whether it is reasonable to demand of this 
class C to be able to generate the results of its various casts. This 
would also mean that either the original programmer should somehow be 
aware of all the possible situations that might later arise, or else 
there would be a massive subclassing going on so we can slap in a new 
opCast method each time one is needed.

In trivial cases, like when returning an int, wouldn't it be more 
practical to instead have an int getValue() method? A cast here seems 
overkill. And with the non-trivial cases, one starts to wonder what the 
whole point of the casting is in the first place.

Explicit casting is an ugly hack to begin with. Its original purpose was 
to cheat and lie, to pretend a pointer is an int, and such. This was 
excusable with the performance issues of the day. But today, casts are 
used liberally, automatically (implicitly), and at times for purposes 
that do not stand up to rational scrutiny. And often just because of 
plain sloppiness in workmanship or cognition.

Where a non-trivial class needs to be "converted" to another, it might 
be more logical to have the "receiving" class have the method of 
conversion. This would allow for an unlimited number of receiving 
classes invented as and when needed, without the original class needing 
to know about them.

(And a more universal solution would of course be to have a factory 
class that receives as input the castee in a serialized form.)

But, all this discussion ignores private variables and access rights. 
However you look at it, this whole issue seems error prone, ill 
conceived, and simply a bad idea.

Classes (or actually, instances of classes) should never be explicitly 
cast to other classes. Period.


Implicit casts of classes,

are simply needed for polymorphism, so they should be allowed. But that, 
too, should be restricted to assigning to variables of type <ancestor to 
the class>, or to type <interface of the class or its ancestor>. Nothing 
else.

class Ancestor {}
class Child: Ancestor {}

Ancestor a = new Child();
Child c = a;
Ancestor a2 = c;

No explicit casts should be needed here. (Of course this needs a runtime 
check at "c = a;" to see that the current instance that a refers to, is 
assignable to c. But hey, we have bounds checking too in D!)


I think casting oranges to footballs is bad practice. Whenever one finds 
himself even considering it, one should trash the blueprints and start 
over.

And if, for "unavoidable external reasons", one does really need the 
contents of an orange transferred to a football, then I'd suggest an 
intermediate class SuckAppleAndBlowFootball.

---

D is a language that makes a difference between built-in types and user 
types (not least by not having an overloadable assignment operator). And 
that is OK, IMHO.

And since this is the case, the above reasoning about restricting 
casting of classes should not sound all that bad. It also means that we 
have no obligation to keep the implicit casting rules for built-ins 
similar to those of classes.



More information about the Digitalmars-d mailing list