I'm not going to say it should be removed, but I'm just wondering if this is
really needed anymore, or maybe to! should instead make use of it.
opCast provides a means to convert an object/struct of one type to another
through an explicit cast operation. This is good as it allows generic code to
perform conversions through a standard call, and the result is a usable type.
I would like to advocate the use of to!() more often in D code than cast(). It
is much more robust, though has slightly different behavior (throws an
exception on class conversions error).
The main issue I see is that we can now convert classes in two forms. To will
make use of both on opCast function and a to function that is found in the
class. (opCast taking precedence in to!). The behavior for using these are
quite different, and be a reason to keep them distinct. In which case this is
just an informative message about their behavior and I'll add it to a wiki.
The example below shows 3 things:
* order of precedence is: opCast, cast, to
* defining opCast can disable casting to any type (its existence prevents
normal casting operations from happening)
* the declared to!() function is not used when an opCast exists but doesn't
match.
Maybe the last one should be fixed.
Here is the code:
import std.conv;
void main() {
B b = new B;
b.i = 5;
A ab = b;
B bcast = cast(B) ab;
assert(b.i == bcast.i); // Fail: used opCast function
B bto = to!B(ab);
assert(b.i == bto.i); // Fail: used opCast function
C c = new C;
c.i = 5;
A ac = c;
//C ccast = cast(C) ac; // Doesn't compile: uses opCast
//C cto = to!C(ac); // Doesn't compile: uses opCast
//
// test.d(13): Error: template instance opCast!(C)
// does not match template declaration opCast(T) if (is(T == B))
//
//assert(c.i == ccast.i);
//assert(c.i == cto.i);
E e = new E;
e.i = 5;
D de = e;
E ecast = cast(E) de;
assert(e.i == ecast.i); // Pass: uses cast
E eto = to!E(de);
assert(e.i == eto.i); // Pass: uses cast
}
class A {
B opCast(T)() if(is(T == B)) {
return new B;
}
C to(T)() if(is(T == C)) {
auto b = new B;
b.i = 5;
return b;
}
}
class B : A {
int i;
}
class C : A {
int i;
}
class D {
E to(T)() if(is(T == E)) {
return new E;
}
}
class E : D {
int i;
}

I'm not going to say it should be removed, but I'm just wondering if this is
really needed anymore, or maybe to! should instead make use of it.
opCast provides a means to convert an object/struct of one type to another
through an explicit cast operation. This is good as it allows generic code to
perform conversions through a standard call, and the result is a usable type.
I would like to advocate the use of to!() more often in D code than cast(). It
is much more robust, though has slightly different behavior (throws an
exception on class conversions error).
The main issue I see is that we can now convert classes in two forms. To will
make use of both on opCast function and a to function that is found in the
class. (opCast taking precedence in to!). The behavior for using these are
quite different, and be a reason to keep them distinct. In which case this is
just an informative message about their behavior and I'll add it to a wiki.
The example below shows 3 things:
* order of precedence is: opCast, cast, to
* defining opCast can disable casting to any type (its existence prevents
normal casting operations from happening)
* the declared to!() function is not used when an opCast exists but doesn't
match.
Maybe the last one should be fixed.
Here is the code:
import std.conv;
void main() {
B b = new B;
b.i = 5;
A ab = b;
B bcast = cast(B) ab;
assert(b.i == bcast.i); // Fail: used opCast function
B bto = to!B(ab);
assert(b.i == bto.i); // Fail: used opCast function
C c = new C;
c.i = 5;
A ac = c;
//C ccast = cast(C) ac; // Doesn't compile: uses opCast
//C cto = to!C(ac); // Doesn't compile: uses opCast
//
// test.d(13): Error: template instance opCast!(C)
// does not match template declaration opCast(T) if (is(T ==
B))
//
//assert(c.i == ccast.i);
//assert(c.i == cto.i);
E e = new E;
e.i = 5;
D de = e;
E ecast = cast(E) de;
assert(e.i == ecast.i); // Pass: uses cast
E eto = to!E(de);
assert(e.i == eto.i); // Pass: uses cast
}
class A {
B opCast(T)() if(is(T == B)) {
return new B;
}
C to(T)() if(is(T == C)) {
auto b = new B;
b.i = 5;
return b;
}
}
class B : A {
int i;
}
class C : A {
int i;
}
class D {
E to(T)() if(is(T == E)) {
return new E;
}
}
class E : D {
int i;
}

IMHO, coercions in D should be redesigned. They are a tiny bit better than C
but C is a weekly (and poorly) typed language. I personally prefer the properly
strongly typed ML family of languages.
My preference is as follows:
1. static_cast:
a. Remove ALL implicit coercions inherited from c such as double -> int,
b. I don't see the need for an operator for conversions since they can have
different parameters, e.g.:
- converting to string can have formatting specified
- converting string to numeric types with optional base parameter
- converting integer to floating point specifies round/floor/ceiling/etc..
2. const_cast: should be a _separate_ operator in order to prevent removing
const by mistake.
const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast
3. dynamic_cast: the language should provide a down cast operator for OO.
4. reinterpret_cast: unsafe and should be restricted as much as possible (Not
available in safe code) maybe not provide it at all since it's implementable
via union. A restricted library solution for when you really want to play with
bits and bytes?
the above means that:
double pi = 3.14;
int p = pi; // compile-time error
int p = floor(pi); // ok
and also:
int x = ??; // some number
double y = x; //compile-time error
double z = double(x); // explicit
double r = 5 / 2; // compile error
choose either:
a. double r1 = double(5/2); // 2.0
b. double r2 = double (5) / 2; // 2.5

1. static_cast:
a. Remove ALL implicit coercions inherited from c such as double -> int,
b. I don't see the need for an operator for conversions since they can have
different parameters, e.g.:
- converting to string can have formatting specified
- converting string to numeric types with optional base parameter
- converting integer to floating point specifies round/floor/ceiling/etc..
2. const_cast: should be a _separate_ operator in order to prevent removing
const by mistake.
const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast
3. dynamic_cast: the language should provide a down cast operator for OO.
4. reinterpret_cast: unsafe and should be restricted as much as possible (Not
available in safe code) maybe not provide it at all since it's implementable
via union. A restricted library solution for when you really want to play with
bits and bytes?

There are some ideas here, like the separation from const_cast, dynamic cast,
and other casts. In past I too have asked for something similar, but I think
Walter was not interested.
I guess the idea of having a single cast is to keep the language simple. But
those _are_ different kinds of casts, they have different semantics. Lumping
different semantics into the same syntax is not a good way to simplify a
language, in my opinion. It just creates obscurity and maybe some other
troubles too.
Bye,
bearophile

1. static_cast:
a. Remove ALL implicit coercions inherited from c such as double ->
int, b. I don't see the need for an operator for conversions since
they can have different parameters, e.g.: - converting to string can
have formatting specified
- converting string to numeric types with optional base parameter
- converting integer to floating point specifies
round/floor/ceiling/etc..
2. const_cast: should be a _separate_ operator in order to prevent
removing const by mistake.
const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast
3. dynamic_cast: the language should provide a down cast operator for OO.
4. reinterpret_cast: unsafe and should be restricted as much as possible
(Not available in safe code) maybe not provide it at all since it's
implementable via union. A restricted library solution for when you
really want to play with bits and bytes?

There are some ideas here, like the separation from const_cast, dynamic
cast, and other casts. In past I too have asked for something similar, but
I think Walter was not interested.
I guess the idea of having a single cast is to keep the language simple.
But those _are_ different kinds of casts, they have different semantics.
Lumping different semantics into the same syntax is not a good way to
simplify a language, in my opinion. It just creates obscurity and maybe
some other troubles too.

And how many programmers do you know who actually, really know the differences
between the 4 C++ cast types. _I_'m not sure that _I_ know, and I've studied
it.
And honestly, in most cases - if not in _all_ cases - as far as I can tell, the
compiler should be able to determine the correct cast type. So, forcing that on
the programmer is just stupid. If you actually _need_ separate cast types, then
we should have them, but if we can avoid that, we definitely should. I think
that
the fact that C++ has so many types of casts is horrible. I try and use them
correctly, but I don't think that there are very many programmers (percentage-
wise at least) who do. I know plenty of programmers who just use C-style casts
everywhere.
- Jonathan M Davis

1. static_cast:
a. Remove ALL implicit coercions inherited from c such as double -> int,
b. I don't see the need for an operator for conversions since they can have

different parameters, e.g.:

- converting to string can have formatting specified
- converting string to numeric types with optional base parameter
- converting integer to floating point specifies round/floor/ceiling/etc..
2. const_cast: should be a _separate_ operator in order to prevent removing

const by mistake.

const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast
3. dynamic_cast: the language should provide a down cast operator for OO.
4. reinterpret_cast: unsafe and should be restricted as much as possible (Not

available in safe code) maybe not provide it at all since it's implementable
via
union. A restricted library solution for when you really want to play with bits
and bytes?

There are some ideas here, like the separation from const_cast, dynamic cast,

and other casts. In past I too have asked for something similar, but I think
Walter was not interested.

I guess the idea of having a single cast is to keep the language simple. But

those _are_ different kinds of casts, they have different semantics. Lumping
different semantics into the same syntax is not a good way to simplify a
language,
in my opinion. It just creates obscurity and maybe some other troubles too.

Bye,
bearophile

How about the following.
T1 a;
T2 b;
b = cast(T2, T1) a;
The difference between the two types would be clearly visible.

IMHO, coercions in D should be redesigned. They are a tiny bit better than C
but C is a weekly (and poorly) typed language. I personally prefer the properly
strongly typed ML family of languages.
My preference is as follows:
1. static_cast:
a. Remove ALL implicit coercions inherited from c such as double -> int,

Done

b. I don't see the need for an operator for conversions since they can have
different parameters, e.g.:
- converting to string can have formatting specified
- converting string to numeric types with optional base parameter
- converting integer to floating point specifies round/floor/ceiling/etc..

This was kind of my point, to! already specifies how to generically (an
important part) to other types. And opCast overrides everything (which I don't
wish to claim is incorrect, just asking).

2. const_cast: should be a _separate_ operator in order to prevent removing
const by mistake.
const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast

I think to! should be changed such that this would be a ConvException.

3. dynamic_cast: the language should provide a down cast operator for OO.

Then the example above is invalid, though still valid when casting const double
to int...

4. reinterpret_cast: unsafe and should be restricted as much as possible (Not
available in safe code) maybe not provide it at all since it's implementable
via union. A restricted library solution for when you really want to play with
bits and bytes?
the above means that:
double pi = 3.14;
int p = pi; // compile-time error

Currently is an error.

int p = floor(pi); // ok

Maybe std.math.floor should return an int, since they are implicitly converted
to real...

IMHO, coercions in D should be redesigned. They are a tiny bit better than C
but C is a weekly (and poorly) typed language. I personally prefer the properly
strongly typed ML family of languages.
My preference is as follows:
1. static_cast:
a. Remove ALL implicit coercions inherited from c such as double -> int,

Done

b. I don't see the need for an operator for conversions since they can have
different parameters, e.g.:
- converting to string can have formatting specified
- converting string to numeric types with optional base parameter
- converting integer to floating point specifies round/floor/ceiling/etc..

This was kind of my point, to! already specifies how to generically (an
important part) to other types. And opCast overrides everything (which I don't
wish to claim is incorrect, just asking).

I don't follow as to how this is important to have a generic interface. Can I
specify parameters for conversion with to! as in my examples?
I'd appreciate an example

2. const_cast: should be a _separate_ operator in order to prevent removing
const by mistake.
const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast

I think to! should be changed such that this would be a ConvException.

This should not even compile. a run-time exception is better than current D but
is still very weak.

3. dynamic_cast: the language should provide a down cast operator for OO.

Then the example above is invalid, though still valid when casting const
double to int...

a down cast should _only_ perform dynamic down casts in the OO sense. so:
Base foo = new Derived;
Derived bar = downCast(foo); // compiles. performed at run-time
[const] double -> int is not a down cast, it is a conversion.

4. reinterpret_cast: unsafe and should be restricted as much as possible (Not
available in safe code) maybe not provide it at all since it's implementable
via union. A restricted library solution for when you really want to play with
bits and bytes?
the above means that:
double pi = 3.14;
int p = pi; // compile-time error

Currently is an error.

int p = floor(pi); // ok

Maybe std.math.floor should return an int, since they are implicitly converted
to real...

1. static_cast:
a. Remove ALL implicit coercions inherited from c such as double ->
int, b. I don't see the need for an operator for conversions since
they can have different parameters, e.g.: - converting to string can
have formatting specified
- converting string to numeric types with optional base parameter
- converting integer to floating point specifies
round/floor/ceiling/etc..
2. const_cast: should be a _separate_ operator in order to prevent
removing const by mistake.
const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast
3. dynamic_cast: the language should provide a down cast operator for OO.
4. reinterpret_cast: unsafe and should be restricted as much as possible
(Not available in safe code) maybe not provide it at all since it's
implementable via union. A restricted library solution for when you
really want to play with bits and bytes?

There are some ideas here, like the separation from const_cast, dynamic
cast, and other casts. In past I too have asked for something similar, but
I think Walter was not interested.
I guess the idea of having a single cast is to keep the language simple.
But those _are_ different kinds of casts, they have different semantics.
Lumping different semantics into the same syntax is not a good way to
simplify a language, in my opinion. It just creates obscurity and maybe
some other troubles too.

And how many programmers do you know who actually, really know the differences
between the 4 C++ cast types. _I_'m not sure that _I_ know, and I've studied
it.
And honestly, in most cases - if not in _all_ cases - as far as I can tell,
the
compiler should be able to determine the correct cast type. So, forcing that
on
the programmer is just stupid. If you actually _need_ separate cast types,
then
we should have them, but if we can avoid that, we definitely should. I think
that
the fact that C++ has so many types of casts is horrible. I try and use them
correctly, but I don't think that there are very many programmers (percentage-
wise at least) who do. I know plenty of programmers who just use C-style casts
everywhere.
- Jonathan M Davis

My suggestion is much simpler than c++.
the _language_ needs only to provide two operators:
down cast operator and const cast operator.
interpret cast is a corner case that can also be implemented as a library
utility.
conversions can and should be done with regular D code (functions). which is
not far from current D idioms (to!).

My suggestion is much simpler than c++.
the _language_ needs only to provide two operators:
down cast operator and const cast operator.
interpret cast is a corner case that can also be implemented as a library
utility. conversions can and should be done with regular D code
(functions). which is not far from current D idioms (to!).

Personally, I think that const_cast is _the_ most pointless cast operator of
the
lot. Simply cast, and if const is part of the new type and wasn't part of the
old one, then it's adding const-ness. If const isn't part of the new type and
it
was part of the old one, then it's removing constness. Adding the extra
complexity just to make sure that you didn't accidentally add or remove const
seems to be totally overkill to me. And since casting away const in D is
technically undefined behavior anyway, does it even make sense to add a
specific
operator for it?
- Jonathan M Davis

My suggestion is much simpler than c++.
the _language_ needs only to provide two operators:
down cast operator and const cast operator.
interpret cast is a corner case that can also be implemented as a library
utility. conversions can and should be done with regular D code
(functions). which is not far from current D idioms (to!).

Personally, I think that const_cast is _the_ most pointless cast operator of
the
lot. Simply cast, and if const is part of the new type and wasn't part of the
old one, then it's adding const-ness. If const isn't part of the new type and
it
was part of the old one, then it's removing constness. Adding the extra
complexity just to make sure that you didn't accidentally add or remove const
seems to be totally overkill to me. And since casting away const in D is
technically undefined behavior anyway, does it even make sense to add a
specific
operator for it?
- Jonathan M Davis

The problem is that it's unsafe across type changes. Consider:
const T x;
void foo(T);
foo(cast(T)x); // drop const, it happens to be safe for some reason
What happens when the type of x changes? Finding all casts of x across all the
code that might reference x is problematic. When all you want to do is
manipulate the constness, being forced to do so via repeating the type means
your code is more fragile than it needs to be.
Later,
Brad

3. dynamic_cast: the language should provide a down cast operator for OO.

Then the example above is invalid, though still valid when casting const
double to int...

a down cast should _only_ perform dynamic down casts in the OO sense. so:
Base foo = new Derived;
Derived bar = downCast(foo); // compiles. performed at run-time
[const] double -> int is not a down cast, it is a conversion.

I was referring to the need for const_cast

Maybe std.math.floor should return an int, since they are implicitly converted
to real...

besides the overflow issue you have mentioned, I also don't want special
cases. No implicit conversions should be applied equally everywhere.

Then be explicit in all of _your_ code. That won't stop others from using
implicit conversion, but you can just assume they are of the same type and be
fine.

Now that I'm clearer on my own stance I should state my view on this. D has
some unique rules for implicit conversion. You'll notice many of your
complaints were _not_ valid in D. D allows for more implicit conversions then
languages like C#, but not at the same cost as C (loss of data). For this
reason I think experience from other languages can not dictate that implicit
conversion is bad/unsafe in D.
The desire to specify specific explicit conversions is understandable, as it
prevents conversions that weren't expected. Cast should be avoided, D's
implicit conversion rules help _prevent_ miss use of this drastically unsafe
tool as you can just make assignments and issues are compiler errors which
bring to your attention the problem. This is one of the reasons I want to
restrict what to! allows for conversions.
So we have:
Safe conversions: implicit
Type conversion: to!()
Unsafe/forced/qualifier conversions: cast
Even qualifier conversions have some library support to avoid using cast:
std.exception.assumeUnique!() (maybe that should be in std.conv? Made sense in
std.contract but not really exception).

This was kind of my point, to! already specifies how to generically (an
important part) to other types. And opCast overrides everything (which I don't
wish to claim is incorrect, just asking).

I don't follow as to how this is important to have a generic interface. Can I
specify parameters for conversion with to! as in my examples?
I'd appreciate an example

Oops, sorry, though I don't see why it can't be specified in to!.

how would the to! usage look like with these additions? I suspect at that stage
the benefits of to! genericity will be lost.
to!(int)("1010101", 2); / base 2 ?
to!(int)(3.14, ..); // how do you specify a floor strategy here, enum?
this quickly gets messy, ugly and redundant.
int a = floor(3.14); // KISS - much better

2. const_cast: should be a _separate_ operator in order to prevent removing
const by mistake.
const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast

I think to! should be changed such that this would be a ConvException.

This should not even compile. a run-time exception is better than current D
but is still very weak.

3. dynamic_cast: the language should provide a down cast operator for OO.

Then the example above is invalid, though still valid when casting const
double to int...

a down cast should _only_ perform dynamic down casts in the OO sense. so:
Base foo = new Derived;
Derived bar = downCast(foo); // compiles. performed at run-time
[const] double -> int is not a down cast, it is a conversion.

I was referring to the need for const_cast

Sorry, I lost you here. what are you talking about here?

Maybe std.math.floor should return an int, since they are implicitly converted
to real...

Other than overflow, which isn't fixed if made explicit, I don't see an issue
with it being implicit.

besides the overflow issue you have mentioned, I also don't want special
cases. No implicit conversions should be applied equally everywhere.

Then be explicit in all of _your_ code. That won't stop others from using
implicit conversion, but you can just assume they are of the same type and be
fine.

since the entire point is to prevent bugs by having compiler checks, I don't
see how the above conclusion helps me at all. I want the compiler to prevent me
from getting the kinds of bugs previously shown.

how would the to! usage look like with these additions? I suspect at that
stage the benefits of to! genericity will be lost.
to!(int)("1010101", 2); / base 2 ?

to!(int)(base!(2)("1010101"));
base!() returns a struct which can be created with strings/int/... and to! can
change it to the different representations?

to!(int)(3.14, ..); // how do you specify a floor strategy here, enum?
this quickly gets messy, ugly and redundant.

to!(int)(floor(3.14));

int a = floor(3.14); // KISS - much better

floor is not a type conversion! I could agree the type of floor should be an
int, but it is not converting a real to an int.
double a = cast(double) floor(3.14);
Do you really want that?

a down cast should _only_ perform dynamic down casts in the OO sense. so:
Base foo = new Derived;
Derived bar = downCast(foo); // compiles. performed at run-time
[const] double -> int is not a down cast, it is a conversion.

I was referring to the need for const_cast

Sorry, I lost you here. what are you talking about here?

Sorry, I am trying to shortcut on explanation.
What I mean is, if you have a dynamic_cast operator you would not have the
issue of casting away const when you meant to downcast.
"const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast"
If you had dynamic cast, you won't use cast to change downcast. The implied
question was, why do you need a const_cast then?
But you are asking for only having const_cast and dynamic_cast, so it makes
sense, oh and static_cast.
To me, I don't see a need to distinguish between dynamic and static cast in D.
These are not concepts you are going to confuse and in general don't even
compile together:
auto a = cast(double) b;
If b is a class it won't compile (with the exception of opCast, which implies
it is safe to cast to double anyway).
But I think the implicit casting of D is important. It provides a way to do
"safe" conversions allowing code to look cleaner. You shouldn't need to
question if an assignment is performing a conversion that is causing an issue
in your code, when using D.
The type you are assigning too might be an issue, but this not a bug introduced
by the conversion. For example you can assign a real to a float implicitly.
This could result in a loss of precision. The bug did not come from an implicit
conversion to float, it came because the precision of real was needed but float
was used.
My initial thought was it was a bad idea, but I came up with that reasoning to
make myself feel good about D :D

Then be explicit in all of _your_ code. That won't stop others from using
implicit conversion, but you can just assume they are of the same type and be
fine.

since the entire point is to prevent bugs by having compiler checks, I don't
see how the above conclusion helps me at all. I want the compiler to prevent me
from getting the kinds of bugs previously shown.

The compiler _is_ checking the code. There is nothing inherently wrong with
converting an int to a double, except larger numbers can be held in an int (but
making the conversion explicit will not resolve this, and won't result in
people considering it). The example of:
double d = 5 / 2;
Is one place I agree could use an explicit conversion to double. I think this
is the only major logic bug solved by forcing type conversions. But I also
believe when the compiler complains the solution to fix it will be:
double d = cast(double) 5 / 2;
Even though it needs to wrap the five/two. That is because a complaining
compiler does not make a thinking programmer, and the more it complains the
less thinking. If you want say that the programmer sucks if they don't think
about the changes they are making then, they also suck when they don't think 5
/ 2 returns an int.

how would the to! usage look like with these additions? I suspect at that
stage the benefits of to! genericity will be lost.
to!(int)("1010101", 2); / base 2 ?

to!(int)(base!(2)("1010101"));
base!() returns a struct which can be created with strings/int/... and to! can
change it to the different representations?

to!(int)(3.14, ..); // how do you specify a floor strategy here, enum?
this quickly gets messy, ugly and redundant.

to!(int)(floor(3.14));

int a = floor(3.14); // KISS - much better

floor is not a type conversion! I could agree the type of floor should be an
int, but it is not converting a real to an int.
double a = cast(double) floor(3.14);
Do you really want that?

a down cast should _only_ perform dynamic down casts in the OO sense. so:
Base foo = new Derived;
Derived bar = downCast(foo); // compiles. performed at run-time
[const] double -> int is not a down cast, it is a conversion.

I was referring to the need for const_cast

Sorry, I lost you here. what are you talking about here?

Sorry, I am trying to shortcut on explanation.
What I mean is, if you have a dynamic_cast operator you would not have the
issue of casting away const when you meant to downcast.
"const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast"
If you had dynamic cast, you won't use cast to change downcast. The implied
question was, why do you need a const_cast then?
But you are asking for only having const_cast and dynamic_cast, so it makes
sense, oh and static_cast.
To me, I don't see a need to distinguish between dynamic and static cast in D.
These are not concepts you are going to confuse and in general don't even
compile together:
auto a = cast(double) b;
If b is a class it won't compile (with the exception of opCast, which implies
it is safe to cast to double anyway).
But I think the implicit casting of D is important. It provides a way to do
"safe" conversions allowing code to look cleaner. You shouldn't need to
question if an assignment is performing a conversion that is causing an issue
in your code, when using D.
The type you are assigning too might be an issue, but this not a bug
introduced by the conversion. For example you can assign a real to a float
implicitly. This could result in a loss of precision. The bug did not come from
an implicit conversion to float, it came because the precision of real was
needed but float was used.
My initial thought was it was a bad idea, but I came up with that reasoning to
make myself feel good about D :D

Then be explicit in all of _your_ code. That won't stop others from using
implicit conversion, but you can just assume they are of the same type and be
fine.

since the entire point is to prevent bugs by having compiler checks, I don't
see how the above conclusion helps me at all. I want the compiler to prevent me
from getting the kinds of bugs previously shown.

The compiler _is_ checking the code. There is nothing inherently wrong with
converting an int to a double, except larger numbers can be held in an int (but
making the conversion explicit will not resolve this, and won't result in
people considering it). The example of:
double d = 5 / 2;
Is one place I agree could use an explicit conversion to double. I think this
is the only major logic bug solved by forcing type conversions. But I also
believe when the compiler complains the solution to fix it will be:
double d = cast(double) 5 / 2;
Even though it needs to wrap the five/two. That is because a complaining
compiler does not make a thinking programmer, and the more it complains the
less thinking. If you want say that the programmer sucks if they don't think
about the changes they are making then, they also suck when they don't think 5
/ 2 returns an int.

I did a language proposal on this some time back, which was accepted,
but which I haven't got around to making a patch for yet. The idea is
that integer division (5 / 2) involves a discarding of the fractional part.
The fact can be tracked as part of the integer range propagation (it is
an int with a discarded fraction). An int with a discarded fraction
cannot be implicitly converted to double. It can give a very informative
error message too.
That will catch this particular bug (which is a moderately common one).

how would the to! usage look like with these additions? I suspect at that
stage the benefits of to! genericity will be lost.
to!(int)("1010101", 2); / base 2 ?

to!(int)(base!(2)("1010101"));

semantically this is what i wanted but i still feel that a plain function would
be easier on the eyes.
for instance:
int r = parseInt("101010", 2);
// second parameter is optional and defaults to decimal base

base!() returns a struct which can be created with strings/int/... and to! can
change it to the different representations?

to!(int)(3.14, ..); // how do you specify a floor strategy here, enum?
this quickly gets messy, ugly and redundant.

to!(int)(floor(3.14));

int a = floor(3.14); // KISS - much better

floor is not a type conversion! I could agree the type of floor should be an
int, but it is not converting a real to an int.
double a = cast(double) floor(3.14);

a down cast should _only_ perform dynamic down casts in the OO sense. so:
Base foo = new Derived;
Derived bar = downCast(foo); // compiles. performed at run-time
[const] double -> int is not a down cast, it is a conversion.

I was referring to the need for const_cast

Sorry, I lost you here. what are you talking about here?

Sorry, I am trying to shortcut on explanation.
What I mean is, if you have a dynamic_cast operator you would not have the
issue of casting away const when you meant to downcast.
"const Base obj1 = new Derived();
auto obj2 = cast(Derived)(obj1); // oops: meant to only down cast"
If you had dynamic cast, you won't use cast to change downcast. The implied
question was, why do you need a const_cast then?
But you are asking for only having const_cast and dynamic_cast, so it makes
sense, oh and static_cast.

Thanks for explaining.
As you said, I want only const_cast and down_cast operators to be provided by
the language.

To me, I don't see a need to distinguish between dynamic and static cast in D.
These are not concepts you are going to confuse and in general don't even
compile together:
auto a = cast(double) b;
If b is a class it won't compile (with the exception of opCast, which implies
it is safe to cast to double anyway).

IMO, there is a need to distinguish the two because I may want to provide a
conversion of my class type to a different class.
contrived example:
class Person {};
class Kid : Person {};
class Adult : Person {};
I want to be able to convert a Kid instance into an Adult instance when said
kid turns 18.

But I think the implicit casting of D is important. It provides a way to do
"safe" conversions allowing code to look cleaner. You shouldn't need to
question if an assignment is performing a conversion that is causing an issue
in your code, when using D.
The type you are assigning too might be an issue, but this not a bug
introduced by the conversion. For example you can assign a real to a float
implicitly. This could result in a loss of precision. The bug did not come from
an implicit conversion to float, it came because the precision of real was
needed but float was used.
My initial thought was it was a bad idea, but I came up with that reasoning to
make myself feel good about D :D

My opinion - this is a misfeature inherited from C. Assignment of incorrect
type (e.g. a double value to an int) should be a compile-time error.

Then be explicit in all of _your_ code. That won't stop others from using
implicit conversion, but you can just assume they are of the same type and be
fine.

since the entire point is to prevent bugs by having compiler checks, I don't
see how the above conclusion helps me at all. I want the compiler to prevent me
from getting the kinds of bugs previously shown.

The compiler _is_ checking the code. There is nothing inherently wrong with
converting an int to a double, except larger numbers can be held in an int (but
making the conversion explicit will not resolve this, and won't result in
people considering it). The example of:

because of differences in representation this is also unsafe. Not all integral
values can be represented accurately in a floating point type and this has
nothing to do with size of int. I myself had such a bug where I expected a
value of 2.0 as a result of some calculation but got 1.99998.. instead.

double d = 5 / 2;
Is one place I agree could use an explicit conversion to double. I think this
is the only major logic bug solved by forcing type conversions. But I also
believe when the compiler complains the solution to fix it will be:
double d = cast(double) 5 / 2;
Even though it needs to wrap the five/two. That is because a complaining
compiler does not make a thinking programmer, and the more it complains the
less thinking. If you want say that the programmer sucks if they don't think
about the changes they are making then, they also suck when they don't think 5
/ 2 returns an int.

i disagree with this logic. Take a look at ML family of languages to see that
more checks do not make worse programmers.

semantically this is what i wanted but i still feel that a plain function
would be easier on the eyes.
for instance:
int r = parseInt("101010", 2);
// second parameter is optional and defaults to decimal base

But then the logic for base conversion is spread out in:
parseInt, parseDouble, toString, and what ever else a base conversion might be
converted to/from. Though a helper function would be used by all.
And how do you handle generic code?
static if(is(T == int) parseInt...
else static if(is(T == double)) parseDouble...

Yes, yes you do. Well you are in luck:
int a = floor(3.14); // does not compile in D
I think returning integer would be correct, but doesn't bother me to much?
(Anyone else reading with an opinion?... numeric coders?)

IMO, there is a need to distinguish the two because I may want to provide a
conversion of my class type to a different class.
contrived example:
class Person {};
class Kid : Person {};
class Adult : Person {};
I want to be able to convert a Kid instance into an Adult instance when said
kid turns 18.

Currently you can provide the conversion in the manner you desire
Adult grownup = kid.canSmokeNow();
And by _not_ providing an opCast function, casting from Kid to adult will fail!
to compile. Now of the cast types I do not know where this one falls, but
dynamic cast is not it (I would think static cast).

The type you are assigning too might be an issue, but this not a bug
introduced by the conversion. For example you can assign a real to a float
implicitly. This could result in a loss of precision. The bug did not come from
an implicit conversion to float, it came because the precision of real was
needed but float was used.
My initial thought was it was a bad idea, but I came up with that reasoning to
make myself feel good about D :D

My opinion - this is a misfeature inherited from C. Assignment of incorrect
type (e.g. a double value to an int) should be a compile-time error.

Could we please get one thing straight, D does not implicitly convert
double/float/real to int. Or int to byte. You can select from these examples:
int -> uint
real -> double -> float
int -> double...
byte -> int
and other similar combinations
But stop using a completely invalid conversion example.

The compiler _is_ checking the code. There is nothing inherently wrong with
converting an int to a double, except larger numbers can be held in an int (but
making the conversion explicit will not resolve this, and won't result in
people considering it). The example of:

because of differences in representation this is also unsafe. Not all integral
values can be represented accurately in a floating point type and this has
nothing to do with size of int. I myself had such a bug where I expected a
value of 2.0 as a result of some calculation but got 1.99998.. instead.

I have never heard this. Not all values are representable in floating point,
but I do not know of any issue representing integers.
http://ideone.com/e8x5L
If you received a value of 1.99998 from a calculation, it is an inherit issue
with using double and not a conversion error from converting an int to a double.

double d = 5 / 2;
Is one place I agree could use an explicit conversion to double. I think this
is the only major logic bug solved by forcing type conversions. But I also
believe when the compiler complains the solution to fix it will be:
double d = cast(double) 5 / 2;
Even though it needs to wrap the five/two. That is because a complaining
compiler does not make a thinking programmer, and the more it complains the
less thinking. If you want say that the programmer sucks if they don't think
about the changes they are making then, they also suck when they don't think 5
/ 2 returns an int.

i disagree with this logic. Take a look at ML family of languages to see that
more checks do not make worse programmers.

I said nothing about making the programmer worse due to checks, but do to
excessive complaining. I do not think a programmer sucks for either mistake; I
do think both are very easy mistakes to make. As Don pointed out there is a
plan to fix this issue (not sure if it applies to when variables are used too).
[OT] Why nagging people makes them numb.
I believe you understand the premise of this. If something continually asks or
tells you to do something, the answer becomes involuntary. Like dialogs that
say do you wish to continue? Well I might not, but by the time I realize that
I've already clicked yes (actually I might realize it 5 mins later and has
nothing to do with being asked the question).
But what I think you want is for the required action to be a safer action. For
example, write now the solution is to insert a cast() which handles many
different things and could perform one you weren't expecting. With many
cast/conversion methods then you insert the appropriate method and it will
complain that it can't do that.
And now that I am seeing your view a little better I don't see this at play
because:
double d = double(5/2);
would induce thinking, but so would:
double d = cast(double)(5/2);
(want an ! in there :P)
I do not wish to argue against making things explicit, but I do want to figure
out if there really is an issue in the way D does implicit conversions. So far
I am seeing an opinion based on experience with C, but not D and an
unwillingness to see that implicit conversion isn't harmful when done right.

semantically this is what i wanted but i still feel that a plain function
would be easier on the eyes.
for instance:
int r = parseInt("101010", 2);
// second parameter is optional and defaults to decimal base

But then the logic for base conversion is spread out in:
parseInt, parseDouble, toString, and what ever else a base conversion might be
converted to/from. Though a helper function would be used by all.
And how do you handle generic code?
static if(is(T == int) parseInt...
else static if(is(T == double)) parseDouble...

I still haven't seen one example of generic code that uses a generic
conversion. I remain unconvinced about this point and would appreciate an
example.
this is however a minor point in the discussion (stylistic issue) so let's move
on to the more important parts.

Yes, yes you do. Well you are in luck:
int a = floor(3.14); // does not compile in D
I think returning integer would be correct, but doesn't bother me to much?
(Anyone else reading with an opinion?... numeric coders?)

IMO, there is a need to distinguish the two because I may want to provide a
conversion of my class type to a different class.
contrived example:
class Person {};
class Kid : Person {};
class Adult : Person {};
I want to be able to convert a Kid instance into an Adult instance when said
kid turns 18.

Currently you can provide the conversion in the manner you desire
Adult grownup = kid.canSmokeNow();
And by _not_ providing an opCast function, casting from Kid to adult will
fail! to compile. Now of the cast types I do not know where this one falls, but
dynamic cast is not it (I would think static cast).

Exactly. I want to be required to write something like the above and _not_
allowed to use an opCast for this case. As you said, this is indeed a static
cast and it should be separate from the down cast provided by cast().

The type you are assigning too might be an issue, but this not a bug
introduced by the conversion. For example you can assign a real to a float
implicitly. This could result in a loss of precision. The bug did not come from
an implicit conversion to float, it came because the precision of real was
needed but float was used.
My initial thought was it was a bad idea, but I came up with that reasoning to
make myself feel good about D :D

My opinion - this is a misfeature inherited from C. Assignment of incorrect
type (e.g. a double value to an int) should be a compile-time error.

Could we please get one thing straight, D does not implicitly convert
double/float/real to int. Or int to byte. You can select from these examples:
int -> uint
real -> double -> float
int -> double...
byte -> int
and other similar combinations
But stop using a completely invalid conversion example.

That was just one example. Let's discuss another one from your list then:
uint foo = -1; // remember that this can be a result of a long calculation
should the above compile in your opinion?

The compiler _is_ checking the code. There is nothing inherently wrong with
converting an int to a double, except larger numbers can be held in an int (but
making the conversion explicit will not resolve this, and won't result in
people considering it). The example of:

because of differences in representation this is also unsafe. Not all integral
values can be represented accurately in a floating point type and this has
nothing to do with size of int. I myself had such a bug where I expected a
value of 2.0 as a result of some calculation but got 1.99998.. instead.

I have never heard this. Not all values are representable in floating point,
but I do not know of any issue representing integers.
http://ideone.com/e8x5L

If you received a value of 1.99998 from a calculation, it is an inherit issue
with using double and not a conversion error from converting an int to a double.

double d = 5 / 2;
Is one place I agree could use an explicit conversion to double. I think this
is the only major logic bug solved by forcing type conversions. But I also
believe when the compiler complains the solution to fix it will be:
double d = cast(double) 5 / 2;
Even though it needs to wrap the five/two. That is because a complaining
compiler does not make a thinking programmer, and the more it complains the
less thinking. If you want say that the programmer sucks if they don't think
about the changes they are making then, they also suck when they don't think 5
/ 2 returns an int.

i disagree with this logic. Take a look at ML family of languages to see that
more checks do not make worse programmers.

I said nothing about making the programmer worse due to checks, but do to
excessive complaining. I do not think a programmer sucks for either mistake; I
do think both are very easy mistakes to make. As Don pointed out there is a
plan to fix this issue (not sure if it applies to when variables are used too).
[OT] Why nagging people makes them numb.
I believe you understand the premise of this. If something continually asks or
tells you to do something, the answer becomes involuntary. Like dialogs that
say do you wish to continue? Well I might not, but by the time I realize that
I've already clicked yes (actually I might realize it 5 mins later and has
nothing to do with being asked the question).
But what I think you want is for the required action to be a safer action. For
example, write now the solution is to insert a cast() which handles many
different things and could perform one you weren't expecting. With many
cast/conversion methods then you insert the appropriate method and it will
complain that it can't do that.

I understand what you mean about the confirmation dialog but as you said
yourself above, I'm not asking for a confirmation dialog but rather using safer
actions.
I think we agree on this.

And now that I am seeing your view a little better I don't see this at play
because:
double d = double(5/2);
would induce thinking, but so would:
double d = cast(double)(5/2);
(want an ! in there :P)

BUT, in the latter case cast(double) can do additional things that I don't need
like remove constancy. cast() is problematic cause it overloads several
semantics actions onto the same syntactic operator.
It's also easier to read / understand code when you see "cast" and you know
that it always means one specific operation (e.g. down cast). You don't need to
read what's inside the cast to figure out if it removes constancy, does a
static type conversion or perhaps a run-time down cast.

I do not wish to argue against making things explicit, but I do want to figure
out if there really is an issue in the way D does implicit conversions. So far
I am seeing an opinion based on experience with C, but not D and an
unwillingness to see that implicit conversion isn't harmful when done right.

I still haven't seen one example of generic code that uses a generic
conversion. I remain unconvinced about this point and would appreciate an
example.
this is however a minor point in the discussion (stylistic issue) so let's
move on to the more important parts.

Good point. I don't have one from experience. I can build on your example:
class Elderly : Person {
Elderly to(Person p) {
Adult adult = to!Adult(p);
return new Elderly(adult);
}
}
The above would throw an exception if p was a Kid. Note that your solution does
not provide compile time checking because you'd still need a dynamic cast to
retrieve an Adult from your person.
Providing a generic abstraction so when someone does find a use is a major
style of Phobos.

That was just one example. Let's discuss another one from your list then:
uint foo = -1; // remember that this can be a result of a long calculation
should the above compile in your opinion?

No, I think int to uint should not be implicit. Maybe there is a reason other
than C inheritance, I'm sure bearophile has a feature request for it.

I have an account so I get 15sec of runtime:
http://ideone.com/9ZvNL
Ok, I'm surprised this is successful. So I made another test that fails on my
local machine, but strangely enough, succeeds on ideone...
http://ideone.com/gOtYc
Any way this demonstration is showing an issue with overflow. I have already
stated that explicit casts do not solve this and got no disagreement from you.

I understand what you mean about the confirmation dialog but as you said
yourself above, I'm not asking for a confirmation dialog but rather using safer
actions.
I think we agree on this.

Yes, we do agree. What we don't agree on is the best way to make things safer.
I am saying that implicit casts are not bad when data is not being lost.
And to! is a good candidate for providing safe conversions (possible data lost
but qualifiers remain).
And that mixing conversions that loose data with ones that transform it (class
conversion) is not an issue.

I still haven't seen one example of generic code that uses a generic
conversion.
I remain unconvinced about this point and would appreciate an example.

Like half the generic code I've written does that. A direct example
for this is my web.d - it makes automatic wrappers for D functions
that are callable through a cgi interface.
D:
int myFunction(float a, string b) { .... }
User's browser goes to:
myprogram/my-function?a=1.5&b=something
And sees the return value. The way the code works is:
(pseudocode)
foreach(member; thing.allMembers) {
member.arguments args;
foreach(i, arg; member.arguments) {
args[i] = to!(typeof(arg))(cgi.get[arg.name]);
}
cgi.write(to!string(member(args)));
}
Everything in the web interface is string based on transport, so generic
conversions are done to and from all the D types used.
I did something similar with the command line version and with
my D2 dmdscript port.