www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Question about iteger literals

reply "Uranuz" <neuranuz gmail.com> writes:
I have the following programme

import std.stdio;

bool isDigit(char c) nothrow
{
	return c >= '0' && c <= '9';
}

ushort hexValue(char c) nothrow
{
	if( isDigit(c) )
		return c - '0';
	else if (c >= 'a' && c <= 'f')
		return c - 'a' + 10;
	else if (c >= 'A' && c <= 'F')
		return c - 'A' + 10;
	else
		return ushort.max;
}


void main()
{
	writeln(hexValue('A'));	
}

This example is compiling successfully in DMD 2.064 but in DMD 
2.065 a got the following error:

/d544/f547.d(12): Error: cannot implicitly convert expression 
(cast(int)c - 48) of type int to ushort
/d544/f547.d(14): Error: cannot implicitly convert expression 
(cast(int)c - 97 + 10) of type int to ushort
/d544/f547.d(16): Error: cannot implicitly convert expression 
(cast(int)c - 65 + 10) of type int to ushort

So I have a question why these expressions are casted to int? I 
was thinking that result should be of char type. And it could be 
implicitly converted to ushort (because there is enough place to 
store result). Is it a bug in compiler or I should insert 
explicit casts?
Jun 22 2014
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Uranuz:

 bool isDigit(char c) nothrow
This function is already in Phobos, it's std.ascii.isDigit.
 ushort hexValue(char c) nothrow
Better to use this signature (assuming you want a ushort result, despite a ubyte suffices and a uint is faster): ushort hexValue(in char c) pure nothrow safe nogc
 	else
 		return ushort.max;
Special error values are not very safe. Consider the usage of a Nullable!(ubyte, ubyte.max) instead, if you can stand the little abstraction penalty.
 why these expressions are casted to int?
Because in C/C++/D if you perform arithmetic operations among types shorter than int you produce an int.
 I was thinking that result should be of char type.
In general it can't be a char.
 And it could be implicitly converted to ushort
 (because there is enough place to store result).
The precedent compiler version was wrong, and the bug has being fixed by the great Kenji. If you have an expression like: char - 'a' + 10 It means: [0, 255] - 87 That is [-87, 168] that can't fit in the [0, 65535] range. Currently in D the range value analysis works only on the current expression, so the information from the "if(c >= 'a' && c <= 'f')" condition is ignored here. There are discussions and even code to fix this: http://forum.dlang.org/thread/lnrc8l$1254$1 digitalmars.com https://github.com/lionello/dmd/compare/if-else-range https://github.com/D-Programming-Language/dmd/pull/3679 But both Walter and Andrei have so far ignored this significant D improvement, so I don't know if and when it will be added. Bye, bearophile
Jun 22 2014
parent reply "Uranuz" <neuranuz gmail.com> writes:
 ushort hexValue(in char c) pure nothrow  safe  nogc


 	else
 		return ushort.max;
I understand what pure, nothrow and safe mean there. But what nogc changes in there so I should use this modifier? Is it logical specifier that this function can be used without garbage collector or what?
Jun 22 2014
next sibling parent reply "Uranuz" <neuranuz gmail.com> writes:
In expression
      return c - 'a' + 10;
I could think that 10 has type int and resulting value promoted 
to the largest type. But I don't understand why in expression 
where both of arguments have type char:
	return c - '0';
I have resulting type int. It's very strange for me and looks 
very buggy)
Jun 22 2014
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Uranuz:

 But I don't understand why in expression where both of 
 arguments have type char:
 	return c - '0';
 I have resulting type int. It's very strange for me and looks 
 very buggy)
In D operations among chars return a int. The same happens in C/C++. If you subtract a char from a char in general you can have a negative result, that can't fit in a char. So what's buggy is your thinking. Bye, bearophile
Jun 22 2014
parent reply "Uranuz" <neuranuz gmail.com> writes:
 In D operations among chars return a int. The same happens in 
 C/C++.

 If you subtract a char from a char in general you can have a 
 negative result, that can't fit in a char. So what's buggy is 
 your thinking.
Ok. Thank you! I never thought about it that way
Jun 22 2014
parent reply "Uranuz" <neuranuz gmail.com> writes:
Another stupid question. Using this logic substraction for two 
uint values should return int too, because it can produce 
negative result. Am I right or not?
Jun 22 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Uranuz:

 Another stupid question. Using this logic substraction for two 
 uint values should return int too, because it can produce 
 negative result. Am I right or not?
There are no stupid questions, there are only some stupid answers. Generally uint - uint generates a result with a [-4_294_967_295, 4__294_967_295] range, that can't fit in an integer. I think D here makes an exception to its rule, to avoid too many casts. Because too many casts make the code even less safe than breaking the range assignments rules. Bye, bearophile
Jun 22 2014
prev sibling parent reply "Uranuz" <neuranuz gmail.com> writes:
On Sunday, 22 June 2014 at 11:57:48 UTC, Uranuz wrote:
 Another stupid question. Using this logic substraction for two 
 uint values should return int too, because it can produce 
 negative result. Am I right or not?
Now this code import std.stdio; void main() { uint a = 50; uint b = 60; auto c = a - b; writeln(typeid(c)); } produce output "uint". It's some breakage in my logic. I am thinking that all integer-like types should behave similar way. I perceive char type as ubyte, that should be printed as symbol when using functions like writeln(). But the folowing example import std.stdio; void main() { ubyte a = 50; ubyte b = 60; auto c = a - b; writeln(typeid(c)); } produces output "int" like you said. Why there are so complicated rules in the *new* language. It's hard to understand the logic.
Jun 22 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Uranuz:

 Why there are so complicated rules in the *new* language.
 It's hard to understand the logic.
Despite D being only 14 years old, one of its rules is to (usually) give the same results if you write code that is valid in C. This means it has to follow many rules of C language. If you try your code in C you will see some similar results. This rule of D is quite handy. Other reasons for the current design of D is that sometimes practicality beats design purity, because D is an engineering product. And I guess another reason is that Walter is not a mathematician nor a computer science theorist, so he has not seen some more principled designs, or he has not appreciated them because of their more formal nature. Bye, bearophile
Jun 22 2014
prev sibling parent reply "Uranuz" <neuranuz gmail.com> writes:
If these rules are not so clear and have some exceptions (but I 
don't understand why they are needed) then some documentation 
needed about this. But I would prefer to have result of uint 
substraction like uint, and char substraction like char. If we 
will changing all the types it will be kind of mess. Using this 
logic we should have some bigger type for int multiplication 
operator to fit in result of multiplication of int.max*int.max. I 
know that some assembler operations do this and multiplication of 
two registers with byte size results in placing product into two 
result register. But in context of higher level programming 
language it's better to have better type consistensy. Or we will 
nead a bigger type to store product for ulong.max*ulong.max 
result. Is it good or not?
Jun 22 2014
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 22 Jun 2014 08:23:45 -0400, Uranuz <neuranuz gmail.com> wrote:

 If these rules are not so clear and have some exceptions (but I don't  
 understand why they are needed) then some documentation needed about  
 this.
See integer promotion rules: http://dlang.org/type.html#Integer%20Promotions And the section below it. -Steve
Jun 23 2014
parent reply "Uranuz" <neuranuz gmail.com> writes:
On Monday, 23 June 2014 at 18:32:38 UTC, Steven Schveighoffer 
wrote:
 On Sun, 22 Jun 2014 08:23:45 -0400, Uranuz <neuranuz gmail.com> 
 wrote:

 If these rules are not so clear and have some exceptions (but 
 I don't understand why they are needed) then some 
 documentation needed about this.
See integer promotion rules: http://dlang.org/type.html#Integer%20Promotions And the section below it. -Steve
I see these rules but when I compile following code and it fails with error it looks VERY stupid. import std.stdio; void main() { ubyte a = 15; ubyte b = 10; ubyte c = a + b; //What is happening there?! AAAAARGH! Are you joking?! } Compilation output: /d837/f382.d(9): Error: cannot implicitly convert expression (cast(int)a + cast(int)b) of type int to ubyte I'm just crazy about it! How could it happen?!
Jul 20 2014
next sibling parent "Uranuz" <neuranuz gmail.com> writes:
 I see these rules but when I compile following code and it 
 fails with error it looks VERY stupid.

 import std.stdio;

 void main()
 {
 	ubyte a = 15;
 	ubyte b = 10;
 	
 	ubyte c = a + b; //What is happening there?! AAAAARGH! Are you 
 joking?!
 	
 }

 Compilation output:
 /d837/f382.d(9): Error: cannot implicitly convert expression 
 (cast(int)a + cast(int)b) of type int to ubyte

 I'm just crazy about it! How could it happen?!
I just should forget about all integer type except *int*, because it make my head just explode!!!
Jul 20 2014
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Uranuz:

 	ubyte a = 15;
 	ubyte b = 10;
 	
 	ubyte c = a + b; //What is happening there?! AAAAARGH! Are you 
 joking?!
In C/C++/D if you sum a types that are smaller than int, you obtain an int. D has copied C for backwards compatibility with C code. Bye, bearophile
Jul 20 2014
parent "Uranuz" <neuranuz gmail.com> writes:
 In C/C++/D if you sum a types that are smaller than int, you 
 obtain an int. D has copied C for backwards compatibility with 
 C code.

 Bye,
 bearophile
Is there any reasoning why this should remain unchainged? How could it break interface between languages? And also this code succesfully compiles and runs in C++. #include <iostream> using namespace std; int main() { unsigned short a = 15; unsigned short b = 10; unsigned short c = a + b; //There is no problem cout << c << endl; return 0; } As D compiler doesn't need to compile C programme and have compatible operations with types. Why we still should keep this garbage?! I don't know the right solution but I believe that previous example illustrates some contradiction in integer types system design or implementation. Why we dont promote *ulong* and *long* to int? Let's also promote string into array of ints?! Can't believe it!
Jul 20 2014
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Uranuz:

 But what  nogc changes in there so I should use this modifier?
nogc will be present in dmd 2.066, it means that the function (and all the functions it calls) can't perform operations that cause a call to GC functions. Sometimes GC operations are a source of performance loss. Bye, bearophile
Jun 22 2014