This comes from a recent small discussion on the D.learn newsgroup, and from an
answer by Daniel Keep:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=18915
There are many possible kinds of casts in D:
- To interpret a sequence of bits in a different way, like a uint as a float, a
double as a fixed array of two ints, a fixed array of 8 bytes into a fixed
array of 2 ints, etc, with no need of an intermediate union definition (And
sometimes I want to convert a class reference to a different class, currently
you can do it with: cast(Foo)cast(Void*)bar).
- To perform a safe dynamic cast between two objects, that can return null.
This operation is a bit slow.
- To perform a conversion, for example from double to an int, with truncation.
In future I can even want a way to tell the compiler how to perform such N to M
conversions, so I can convert an int to its string equivalent, etc.
- To perform a cast between two arrays, where I want to convert (reinterpret)
each item, using a true conversion.
- Maybe there are other kinds of casting (like turning an immutable into a
mutable, an impure into a pure, arg!, etc).
Conflating so much different things in the same cast() syntax is less unsafe
and is less flexible.
In C++ there are 4+1 kinds of casts, they add some complexity. Maybe in D2 just
two different casts can be enough:
- A cast that works at compile time only, with no run time penality (the first
and last type in my list).
- A cast that has to perform some operations at run time (the other kinds of
casts in my list).
I think this is an important enough thing for D2, and it's not a backwards
compatible change, it's not an additive change if you want to do it well
(otherwise if you want to follow the route used by C++ of just discouraging the
usage of the old C cast it can be an additive change, but it increases the
language complexity).
If you want to do this in a good way, you can for example use:
- static_cast() or scast() for the purely compile-time ones.
- dcast() or dynamic_cast(), or just cast() for the run-time ones. Such casts
are a bit safer, so they can use a shorter name.
Another good thing is to make the cast semantics more tidy, aligning the
effects of the casts done on an array literal with the effect of the same cast
done on a run-time array (I think they are a bit different now).
Bye,
bearophile

- A cast that has to perform some operations at run time (the other kinds of
casts in my list).

This was not precise enough: such conversion operations count if they are done
at compile-time too. So you can use a static or dynamic cast at compile-time
too, according to what you need.
Bye,
bearophile

There are many possible kinds of casts in D:
- To interpret a sequence of bits in a different way, like a uint as a
float, a double as a fixed array of two ints, a fixed array of 8 bytes
into a fixed array of 2 ints, etc, with no need of an intermediate union
definition (And sometimes I want to convert a class reference to a
different class, currently you can do it with: cast(Foo)cast(Void*)bar). -
To perform a safe dynamic cast between two objects, that can return null.
This operation is a bit slow. - To perform a conversion, for example from
double to an int, with truncation. In future I can even want a way to tell
the compiler how to perform such N to M conversions, so I can convert an
int to its string equivalent, etc. - To perform a cast between two arrays,
where I want to convert (reinterpret) each item, using a true conversion.
- Maybe there are other kinds of casting (like turning an immutable into a
mutable, an impure into a pure, arg!, etc).
Conflating so much different things in the same cast() syntax is less
unsafe and is less flexible.
In C++ there are 4+1 kinds of casts, they add some complexity. Maybe in D2
just two different casts can be enough: - A cast that works at compile
time only, with no run time penality (the first and last type in my list).
- A cast that has to perform some operations at run time (the other kinds
of casts in my list).
I think this is an important enough thing for D2, and it's not a backwards
compatible change, it's not an additive change if you want to do it well
(otherwise if you want to follow the route used by C++ of just
discouraging the usage of the old C cast it can be an additive change, but
it increases the language complexity).
If you want to do this in a good way, you can for example use:
- static_cast() or scast() for the purely compile-time ones.
- dcast() or dynamic_cast(), or just cast() for the run-time ones. Such
casts are a bit safer, so they can use a shorter name.
Another good thing is to make the cast semantics more tidy, aligning the
effects of the casts done on an array literal with the effect of the same
cast done on a run-time array (I think they are a bit different now).
Bye,
bearophile

C++ is the only language that I'm aware of which has multiple types of
casts, and I don't think that it really adds anything of benefit. C-style
casts are, of course, unsafe, but that doesn't mean that you need a bucket-
load of cast types in order to be safe. Languages like Java and C# manage
safe casting with only one type of cast. Two is definitely better than four,
but I question that we really need more than one.
Can't the compiler figure out which cast is supposed to be used in a given
situation and deal with it internally? Having multiple casts just confuses
things (certainly, I don't think that I know anyone who fully understands
the C++ casts). Really, casts should be quite rare in code anyway. And as
much as I'd like to avoid performance penalties, I'd prefer a performance
penalty in the rare case when I have to cast rather than having to worry
about whether I or anyone else on a project that I'm working on is using the
various cast types correctly. In most C++ code that I've seen, people don't
bother to use anything other than a c-style cast unless they specifically
need one of the C++ casts for a safety reason - like using dynamic_cast to
check whether you can safely cast to a particular type. In almost all cases,
they just use a c-style cast. I think that it would be a huge mistake for D
to have more than one type of cast.
And honestly, I would have thought that the compiler would be able to figure
out the correct cast type internally. And if it can't, should you really be
doing that cast in the first place?
I say keep the current single cast type and leave it at that.
- Jonathan M Davis

Languages like Java and C# manage safe casting with only one type of cast.<

In C# you have implicit and explicit casts (used with the same syntax, I think).

Can't the compiler figure out which cast is supposed to be used in a given
situation and deal with it internally?

In this example the conversion can be a trunc of the float, or it can be a
reinterpret of the bits contained in the float as an int, the compiler can't
tell them apart (currently D performs the trunc/round/ceil, according to the FP
flags):
float x = 10.5;
int y = cast(int)x;
The same happens in the conversions of arrays, as I have explained in the post.

I'd prefer a performance
penalty in the rare case when I have to cast rather than having to worry
about whether I or anyone else on a project that I'm working on is using the
various cast types correctly.

It's not just a matter of performance, it's also a matter of keeping the
semantics more tidy, because currently different operations are conflated in
the same syntax.
I think D programmers can appreciate to have a way to tell apart the two kinds
of casts I have explained, also because 90% of the times you can use the normal
(run-time) cast, that can be called just cast() or dcast(). In most cases
that's what you want, you can use it as the default one, and use a scast or
static_cast when you want to reinterpret the bits of a value, struct or array,
pointer (or class reference).
At the moment cast() performs a static cast on run time arrays, a dynamic cast
on array literals, a dynamic cast on values, a dynamic cast on class
references, and I think a static cast between signed and unsigned integers. And
to convert an integer into a string you need to!(). In my opinion this
situation is a bit too much messy.
Bye,
bearophile

C++ is the only language that I'm aware of which has multiple types of
casts, and I don't think that it really adds anything of benefit.

Really? I think the casts are one of the areas where C++ has a huge
advantage over C. Maybe the new casts are not as important as templates
and RAII, but they're up there in the same category. The best part of
the C++ cast system is that it uses template function syntax, which
allows user-defined casts to use the same syntax.
Casts are yet another issue where moving from C++ to D feels like
regressing to C.

Can't the compiler figure out which cast is supposed to be used in a given
situation and deal with it internally?

That's not the point.

Having multiple casts just confuses
things (certainly, I don't think that I know anyone who fully understands
the C++ casts).

If you don't understand C++ casts, then you don't understand D casts.
They do the same thing; the C++ version is just more explicit about what
it does (and therefore safer and easier to read).
--
Rainer Deyke - rainerd eldwood.com

C++ has 4+1 casts, they are a good amount of complexity, and it's not easy to
learn their difference and purposes. So probably Jonathan is right when he says
many C++ programmers don't use C++ casts well and probably tend to stick to one
or two only. I think casts of C++ are too much complex, as most things in C++
:-)
That's why I have suggested only two casts for D, that differ a lot in
purposes, and where most times you can use just one of them (the one with the
simpler and shorter name) and be happy.
Bye,
bearophile

C++ has 4+1 casts, they are a good amount of complexity, and it's not
easy to learn their difference and purposes.

C++ casts perform three different logical functions:
- Removing cv-qualifiers. (const_cast)
- Reinterpreting raw bytes. (reinterpret_cast)
- Converting values. (static_cast/dynamic_cast)
These are clearly distinct function. Accidentally performing the wrong
type of cast is clearly an error, and should be flagged by the compiler.
Ideally, casts should be (distinct) library functions, not language
features.
The only thing vaguely confusing about the C++ system is the distinction
between static_cast and dynamic_cast. I wouldn't mind seeing those two
merged into a conversion_cast.
--
Rainer Deyke - rainerd eldwood.com

Safely though: It won't allow any wild bit representations. For really
wild stuff, you need to use the C-style cast.

- Converting values. (static_cast/dynamic_cast)

I would like to separate static_cast and dynamic_cast:
- static_cast does two things:
a) can convert values: this does call the user-defined conversion
operators if necessary
b) static_cast also communicates "trust me, this super class *really* is
this subclass." In this latter case, no value is converted; rather, the
type of the pointer value is changed, so that the member access offsets
will be adjusted accordingly later on, when this pointer is used
- dynamic_cast performs only (b) above, but safely: "if this super class
is actually this subclass, set the pointer to point to it". Otherwise
the pointer is set to null. Again, no value conversion here.
Ali