Re: Why is int implicitly convertible to ulong?

2014-02-21 Thread Hannes Steffenhagen

The specific problem here was when working with std.json.

std.json distinguishes between UINTEGER and INTEGER, so I had 
code like


static if(is(T : ulong)) {
// must be UINTEGER
} else static if(is(T : long)) {
// can be either INTEGER or UINTEGER
}


I've since found out about isSigned and isUnsigned, still it was 
mighty confusing for me that the first case was selected for 
signed types.


Re: Why is int implicitly convertible to ulong?

2014-02-21 Thread Jonathan M Davis
On Friday, February 21, 2014 12:41:07 Hannes Steffenhagen wrote:
 The specific problem here was when working with std.json.
 
 std.json distinguishes between UINTEGER and INTEGER, so I had
 code like
 
 static if(is(T : ulong)) {
  // must be UINTEGER
 } else static if(is(T : long)) {
  // can be either INTEGER or UINTEGER
 }
 
 
 I've since found out about isSigned and isUnsigned, still it was
 mighty confusing for me that the first case was selected for
 signed types.

Well, it is using : - which means implicit conversion, which is always 
something that you should be careful with in generic code. Technically, 
something like

struct S
{
ulong ul;
alias ul this;
}

would match it as well, and depending on what the code inside the static if is 
like, it might work, but there's also a good chance that it wouldn't. Using 
is(T == ulong) if you want to require that it be exactly ulong, or 
isUnsigned!T if you want any unsigned integral type. Using implicit conversion 
in generic code _can_ be useful, but you need to be _very_ careful with it.

- Jonathan M Davis


Re: Why is int implicitly convertible to ulong?

2014-02-21 Thread Ali Çehreli

On 02/21/2014 04:41 AM, Hannes Steffenhagen wrote:

The specific problem here was when working with std.json.

std.json distinguishes between UINTEGER and INTEGER, so I had code like

static if(is(T : ulong)) {
 // must be UINTEGER
} else static if(is(T : long)) {
 // can be either INTEGER or UINTEGER
}


I've since found out about isSigned and isUnsigned, still it was mighty
confusing for me that the first case was selected for signed types.


I have something like the following in an experimental std.json code 
that converts to JSONValue.


Since std.json uses long for the value, I attempt to detect data loss 
when the value is a large ulong:


JSONValue to(Target : JSONValue, T)(T value)
{
/* ... */

} else static if (is (T : long)) {
static if (is (T == ulong)) {
enforce(value = long.max,
format(Data loss: %s %s cannot fit a long.,
   T.stringof, value));
}

json.type = JSON_TYPE.INTEGER;
json.integer = value;

} else static if (is (T : real)) {

Ali



Re: Why is int implicitly convertible to ulong?

2014-02-17 Thread Xinok
On Monday, 17 February 2014 at 04:40:52 UTC, Jonathan M Davis 
wrote:

On Sunday, February 16, 2014 21:35:01 Hannes Steffenhagen wrote:

isImplicitlyConvertible!(int,ulong) is true. Maybe this is just
me, but I get the impression that this is quite nuts. Why is an
implicit conversion from a signed to an unsigned type possible?
The other way round would be at least somewhat understandable 
if

there's a static check that the values actually fit.


signed to unsigned conversions (and vice versa) are implicit as 
are
conversions from smaller integral types to larger integral 
types. Converting
from smaller integral types to larger really doesn't cause any 
problems, but
the signed to unsigned (or vice versa) can cause issues - one 
of the biggest
of those being the comparison of signed and unsigned values, 
and IIRC, there
was some discussion on making that a warning or error. However, 
while there
are occasional problems from the conversion being implicit, if 
it weren't
implicit, you'd be forced to cast a lot more when the signed 
and unsigned
types interact, which would lead to messier code and could 
actually increase
the number of bugs, because if you got in the habit of casting 
everywhere to
get the signed to unsigned conversions to work, you'd risk 
accidentally doing
stuff like casting a ulong to int and losing data, since the 
compiler would

assume that you knew what you were doing with the cast.

So, it's a tradeoff, and neither making the signed to unsigned 
(or vice versa)
conversions explicit nor implicit would be without problems. 
Walter went with
it being implicit, which matches what C does. However, unlike 
C, conversions
that actually lose data (e.g. long - int) do require casts so 
that it's
easier to catch those problems. But no data is actually lost 
with a sign
conversions, as casting it back to what it was will result in 
the same value

(unlike with converting to a smaller integral value).

Of slightly bigger concern IMHO is that bool and the character 
types are all
treated as integral types, which is at times useful but also 
risks some
entertaining bugs. But again, it's a matter of tradeoffs. If 
they required
casts when interacting with integral types, then a lot more 
casting would be
required, risking a different set of bugs. There really isn't a 
right answer
as to whether the conversions should be implicit or explicit. 
It just comes

down to the tradeoffs that you prefer.

- Jonathan M Davis


I've been bitten by signed / unsigned comparisons before, and I'm 
sure others have been as well. On the other hand, I can't recall 
any bugs that were due to an explicit cast. I can see how 
explicit casts might cause unexpected bugs (if the original type 
changes but is still a valid cast), but in my personal 
experience, explicit casts are safer than implicit casts.


Walter decided to adopt C-style switches for D, to simplify 
translating code. However, implicit fall-through is notorious for 
causing bugs in C. So as a tradeoff, D still allows fall-through 
but only by explicitly writing goto case;.


We could speculate all day, but ultimately it comes down to 
experience of what works and what doesn't. If something is 
generally safe in practice, then perhaps we're better with 
leaving it alone. But if something is a known nuisance for 
causing bugs, then find a better solution.


Why is int implicitly convertible to ulong?

2014-02-16 Thread Hannes Steffenhagen
isImplicitlyConvertible!(int,ulong) is true. Maybe this is just 
me, but I get the impression that this is quite nuts. Why is an 
implicit conversion from a signed to an unsigned type possible? 
The other way round would be at least somewhat understandable if 
there's a static check that the values actually fit.


Re: Why is int implicitly convertible to ulong?

2014-02-16 Thread Ali Çehreli

On 02/16/2014 01:35 PM, Hannes Steffenhagen wrote:

isImplicitlyConvertible!(int,ulong) is true. Maybe this is just me, but
I get the impression that this is quite nuts. Why is an implicit
conversion from a signed to an unsigned type possible? The other way
round would be at least somewhat understandable if there's a static
check that the values actually fit.


I don't know all of the reasons but it is at least about convenience. It 
is possible to write expressions like 'u + diff' without explicit casts:


ulong u = 10;
int diff = -3;
auto a = u + diff;
static assert(is (typeof(a) == ulong));

Related, the type of 'a' above is implied as ulong due to arithmetic 
conversions, which are sometimes very confusing as well. See Usual 
Arithmetic Conversions here:


  http://dlang.org/type.html

Ali



Re: Why is int implicitly convertible to ulong?

2014-02-16 Thread Xinok
On Sunday, 16 February 2014 at 21:35:02 UTC, Hannes Steffenhagen 
wrote:
isImplicitlyConvertible!(int,ulong) is true. Maybe this is just 
me, but I get the impression that this is quite nuts. Why is an 
implicit conversion from a signed to an unsigned type possible? 
The other way round would be at least somewhat understandable 
if there's a static check that the values actually fit.


IIRC, the way they put it is that information is not lost, so 
you could always cast back to an int and get the original value. 
The same is not true for casting to a smaller type, e.g. int to 
byte, the original value may be lost.


Re: Why is int implicitly convertible to ulong?

2014-02-16 Thread Jonathan M Davis
On Sunday, February 16, 2014 21:35:01 Hannes Steffenhagen wrote:
 isImplicitlyConvertible!(int,ulong) is true. Maybe this is just
 me, but I get the impression that this is quite nuts. Why is an
 implicit conversion from a signed to an unsigned type possible?
 The other way round would be at least somewhat understandable if
 there's a static check that the values actually fit.

signed to unsigned conversions (and vice versa) are implicit as are 
conversions from smaller integral types to larger integral types. Converting 
from smaller integral types to larger really doesn't cause any problems, but 
the signed to unsigned (or vice versa) can cause issues - one of the biggest 
of those being the comparison of signed and unsigned values, and IIRC, there 
was some discussion on making that a warning or error. However, while there 
are occasional problems from the conversion being implicit, if it weren't 
implicit, you'd be forced to cast a lot more when the signed and unsigned 
types interact, which would lead to messier code and could actually increase 
the number of bugs, because if you got in the habit of casting everywhere to 
get the signed to unsigned conversions to work, you'd risk accidentally doing 
stuff like casting a ulong to int and losing data, since the compiler would 
assume that you knew what you were doing with the cast.

So, it's a tradeoff, and neither making the signed to unsigned (or vice versa) 
conversions explicit nor implicit would be without problems. Walter went with 
it being implicit, which matches what C does. However, unlike C, conversions 
that actually lose data (e.g. long - int) do require casts so that it's 
easier to catch those problems. But no data is actually lost with a sign 
conversions, as casting it back to what it was will result in the same value 
(unlike with converting to a smaller integral value).

Of slightly bigger concern IMHO is that bool and the character types are all 
treated as integral types, which is at times useful but also risks some 
entertaining bugs. But again, it's a matter of tradeoffs. If they required 
casts when interacting with integral types, then a lot more casting would be 
required, risking a different set of bugs. There really isn't a right answer 
as to whether the conversions should be implicit or explicit. It just comes 
down to the tradeoffs that you prefer.

- Jonathan M Davis