February 05, 2018
On Mon, Feb 05, 2018 at 10:18:57PM -0500, Steven Schveighoffer via Digitalmars-d wrote:
> On 2/5/18 10:05 PM, Nick Sabalausky (Abscissa) wrote:
> 
> > Right, it wouldn't always get rid of the message, but I would think it should when it's known the value cannot be -128, such as the specific example you posted.
> 
> VRP is only for one statement. That is, once you get to the next statement it "forgets" what the value range is.
[...]

IMO, we should extend this past just one statement. It would lead to more possibilities for optimizations and possibly other features too. Though I understand that Walter has reservations about doing this for some reason.


T

-- 
A bend in the road is not the end of the road unless you fail to make the turn. -- Brian White
February 05, 2018
On Tue, Feb 06, 2018 at 02:45:45AM +0000, Adam D. Ruppe via Digitalmars-d wrote:
> On Tuesday, 6 February 2018 at 02:30:03 UTC, Walter Bright wrote:
> > Maybe not, but casting back and forth between them is ugly. Pascal works this way, and it was one of the things I wound up hating about Pascal, all those ORD and CHR casts.
> 
> It is a bit ironic hearing this from the guy who made a language where you have to cast a byte back to a byte! LOL

+1. Couldn't have said it better! :-D


T

-- 
Food and laptops don't mix.
February 05, 2018
On Tue, Feb 06, 2018 at 01:25:16AM +0000, Rubn via Digitalmars-d wrote: [...]
> Maybe in the future this could be possible:
> 
> static assert("Hello " ~ 10 ~ " world" == "Hello 10 world");
> 
> It'd help with CTFE code, I find having to convert integers to strings a lot. This is cleaner syntax and don't rely on std.conv.to. So it doesn't need to be imported, I'm not sure if DMD uses an intrinsic for that as well.  I hope it does but can't be certain.

No need to wait for the future, you can do this today:

	enum toStr(alias X) = X.stringof;

	enum x = 100;
	pragma(msg, toStr!1);
	pragma(msg, toStr!3.14159);
	pragma(msg, "Hello " ~ toStr!10 ~ " world");
	pragma(msg, "Hello " ~ toStr!x ~ " world");

Note, however, that this doesn't work in CTFE, only at template expansion time.


T

-- 
Programming is not just an act of telling a computer what to do: it is also an act of telling other programmers what you wished the computer to do. Both are important, and the latter deserves care. -- Andrew Morton
February 05, 2018
On 2/5/2018 4:08 PM, Steven Schveighoffer wrote:
> In fact, this works in C:
> 
> char a = 1;
> char b = 2;
> char c = a + b;
> 
> I would actually have no problem if it were this way, as you are clear in your intention. I'm also OK with the way it is now, where it requires the cast. The cast is generally added "because the compiler told me to", but it does make you think about what you really want.

D worked that way initially, too. But people strongly complained that it was unintuitive and buggy.

> clear in your intention

Except it wasn't. People did not expect truncation and had bugs.

The thing is, when there are mixed integer sizes and signedness, there is no intuitive and correct solution. Each set of rules comes with its own set of cases where there are unintuitive behaviors.

D picked a solution which followed the C rules so that debugged C code will not break when transferred to D. This is the correct solution for D. D modified that by requiring a cast any time truncation (i.e. losing bits) would happen. Although this did technically break C compatibility, there was a compile time error generated, so there was no silent breakage.

Changing the semantics would just break a lot of existing, working code in undetectable ways, and then introduce another set of unintuitive behaviors that a while down the pike will result in more of these threads.

There really isn't much one can do other than learn the integral promotion rules. They're only a couple of sentences. We can handle it. (And how 2's complement arithmetic works.)
February 05, 2018
On 2/5/2018 4:08 PM, Steven Schveighoffer wrote:
> I think the CPU has to do extra work to throw away that high bit, no?

So much of software relies on C integer semantics that CPU vendors have optimized their performance for them, so no.

Except for 16 bit shorts. Shorts will exact a penalty :-) and so shorts should only be used for data packing purposes.
February 06, 2018
On Monday, 5 February 2018 at 21:38:23 UTC, Simen Kjærås wrote:
> If you were negating a byte, the code does have compile-time known values, since there's a limit to what you can stuff into a byte. If you weren't, the warning is warranted. I will admit the case of -(-128) could throw it off, though.

D has modular arithmetics across the board so there is no limit to what you can stuff into a byte or int.

But doing all calculations as int instead of byte prevents SIMD optimizations.

February 06, 2018
On Monday, 5 February 2018 at 23:18:58 UTC, Timon Gehr wrote:
> On 05.02.2018 22:56, Walter Bright wrote:

>> It's necessary. Working C expressions cannot be converted to D while introducing subtle changes in behavior.
>> ...
>
> Neither byte nor dchar are C types.

>> The idea is a byte can be implicitly converted to a dchar, but not the other way around. Hence, f(byte) is selected as being the "most specialized" match.
>
> The overloading rules are fine, but byte should not implicitly convert to char/dchar, and char should not implicitly convert to byte.

+10000!!!!
February 06, 2018
On Tuesday, 6 February 2018 at 07:18:59 UTC, Walter Bright wrote:
> Except for 16 bit shorts. Shorts will exact a penalty :-) and so shorts should only be used for data packing purposes.

Which CPU model are you thinking of?



February 06, 2018
On Tuesday, 6 February 2018 at 07:15:33 UTC, Walter Bright wrote:
> The thing is, when there are mixed integer sizes and signedness, there is no intuitive and correct solution. Each set of rules comes with its own set of cases where there are unintuitive behaviors.
So, why doing any promotion at all?
If two different types are used in an arithmetic operation,
the larger of those two types should be the result type.
And if the result would be truncated in some way, return NAN.

Every type should have a NAN value.
For the signed types the extra useless .min is a perfect candidate for a NAN.
That allows -x to always be of the same type as x, which I think is a good thing(tm).

Fortunately, in D is't absolutely easy to define just that kind of types
that fullfill all these requirements. Its about 100 LOC.
I call them sbyte, sword, sint and slong which are even better names than the original ones (because they directly indicate that they are signed and match the unsigned ones).
So I never again bother with the completely nuts builtin signed types.
February 06, 2018
On Tue, Feb 06, 2018 at 10:43:39AM +0000, Dominikus Dittes Scherkl via Digitalmars-d wrote: [...]
> Every type should have a NAN value.  For the signed types the extra useless .min is a perfect candidate for a NAN.  That allows -x to always be of the same type as x, which I think is a good thing(tm).

All I can say to that, is to quote Knuth:

	People who are more than casually interested in computers should
	have at least some idea of what the underlying hardware is like.
	Otherwise the programs they write will be pretty weird. -- D.
	Knuth


> Fortunately, in D is't absolutely easy to define just that kind of types that fullfill all these requirements. Its about 100 LOC.  I call them sbyte, sword, sint and slong which are even better names than the original ones (because they directly indicate that they are signed and match the unsigned ones).  So I never again bother with the completely nuts builtin signed types.

Sure, D gives you the flexibility to do that. But if you need high performance, it will be better to follow the hardware semantics more closely. It's not D that has completely nuts signed types; it's your hardware. :-P (Besides the completely nuts casting rules that has nothing to do with the hardware, that is. That part is a stink we inherited from C.)


T

-- 
Famous last words: I *think* this will work...