www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why do I have to cast arguments from int to byte?

reply Chirs Forest <CF chrisforest.com> writes:
I keep having to make casts like the following and it's really 
rubbing me the wrong way:

void foo(T)(T bar){...}

byte bar = 9;

foo!byte(bar + 1); //Error: function foo!byte.foo (byte bar) is 
not callable using argument types (int)	
foo!byte(cast(byte)(bar + 1));

It wouldn't be so bad if I didn't have to use the word cast 
before each cast, bust since I have to specify both the word cast 
and the cast type and then wrap both the cast type and the value 
in brackets... it just explodes my code into multiple lines of 
unreadable mess.


void foo(T)(T bar, T bar2, T bar3){...}

byte foobar = 12;

foo!byte(foobar + 1, foobar + 22, foobar + 333);
vs.
foo!byte(cast(byte)(foobar + 1), cast(byte)(foobar + 22), 
cast(byte)(foobar + 333));

Why?
Oct 10
next sibling parent Moritz Maxeiner <moritz ucworks.org> writes:
On Tuesday, 10 October 2017 at 19:55:36 UTC, Chirs Forest wrote:
 I keep having to make casts like the following and it's really 
 rubbing me the wrong way:

 void foo(T)(T bar){...}

 byte bar = 9;

 [...]

 Why?
Because of integer promotion [1], which is inherited from C. [1] https://dlang.org/spec/type.html#integer-promotions
Oct 10
prev sibling next sibling parent Igor Shirkalin <mathsoft inbox.ru> writes:
On Tuesday, 10 October 2017 at 19:55:36 UTC, Chirs Forest wrote:
 I keep having to make casts like the following and it's really 
 rubbing me the wrong way:

 void foo(T)(T bar){...}

 byte bar = 9;

 foo!byte(bar + 1); //Error: function foo!byte.foo (byte bar) is 
 not callable using argument types (int)	
 foo!byte(cast(byte)(bar + 1));

 It wouldn't be so bad if I didn't have to use the word cast 
 before each cast, bust since I have to specify both the word 
 cast and the cast type and then wrap both the cast type and the 
 value in brackets... it just explodes my code into multiple 
 lines of unreadable mess.


 void foo(T)(T bar, T bar2, T bar3){...}

 byte foobar = 12;

 foo!byte(foobar + 1, foobar + 22, foobar + 333);
 vs.
 foo!byte(cast(byte)(foobar + 1), cast(byte)(foobar + 22), 
 cast(byte)(foobar + 333));

 Why?
Because int (1) + ubyte (9) = int
Oct 10
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 10 October 2017 at 19:55:36 UTC, Chirs Forest wrote:
 Why?
D inherited a silly rule from C where any arithmetic is promoted to int first. The big difference is D doesn't do implicit narrowing conversion... so x + 1 becomes int, but then int to byte requires an explicit cast (unless the compiler can prove the range in that particular expression - this is called "value range propagation"). I think it has proved to be a bit of a mistake :(
Oct 10
prev sibling next sibling parent rjframe <dlang ryanjframe.com> writes:
On Tue, 10 Oct 2017 19:55:36 +0000, Chirs Forest wrote:

 It wouldn't be so bad if I didn't have to use the word cast before each
 cast, bust since I have to specify both the word cast and the cast type
 and then wrap both the cast type and the value in brackets... it just
 explodes my code into multiple lines of unreadable mess.
 
 
 void foo(T)(T bar, T bar2, T bar3){...}
 
 byte foobar = 12;
 
 foo!byte(foobar + 1, foobar + 22, foobar + 333);
 vs.
 foo!byte(cast(byte)(foobar + 1), cast(byte)(foobar + 22),
 cast(byte)(foobar + 333));
You could wrap the cast in a function to clean it up a bit: void main() { byte foobar = 12; foo!byte((foobar + 1).b, (foobar + 22).b, (foobar + 333).b); } byte b(int n) pure { pragma(inline, true); // Probably not necessary. return cast(byte)n; } void foo(T)(T bar, T bar2, T bar3) { import std.stdio : writeln; import std.string : format; writeln("%s, %s, %s".format(bar, bar2, bar3)); } --Ryan
Oct 10
prev sibling parent reply Daniel Kozak <kozzi11 gmail.com> writes:
You can avoid cast:

void foo(T)(T bar){...}

byte bar = 9;

foo!byte(bar + byte(1));

or

byte bar = 9;
byte num = 1;
foo!byte(bar + num);



On Tue, Oct 10, 2017 at 9:55 PM, Chirs Forest via Digitalmars-d-learn <
digitalmars-d-learn puremagic.com> wrote:

 I keep having to make casts like the following and it's really rubbing me
 the wrong way:

 void foo(T)(T bar){...}

 byte bar = 9;

 foo!byte(bar + 1); //Error: function foo!byte.foo (byte bar) is not
 callable using argument types (int)
 foo!byte(cast(byte)(bar + 1));

 It wouldn't be so bad if I didn't have to use the word cast before each
 cast, bust since I have to specify both the word cast and the cast type and
 then wrap both the cast type and the value in brackets... it just explodes
 my code into multiple lines of unreadable mess.


 void foo(T)(T bar, T bar2, T bar3){...}

 byte foobar = 12;

 foo!byte(foobar + 1, foobar + 22, foobar + 333);
 vs.
 foo!byte(cast(byte)(foobar + 1), cast(byte)(foobar + 22),
 cast(byte)(foobar + 333));

 Why?
Oct 11
parent reply kdevel <kdevel vogtner.de> writes:
On Wednesday, 11 October 2017 at 07:09:26 UTC, Daniel Kozak wrote:
 You can avoid cast:

 void foo(T)(T bar){...}

 byte bar = 9;

 foo!byte(bar + byte(1));
Sure? --- void foo(T)(T bar) { } byte bar = 9; void main () { foo!byte(bar + byte(1)); } --- byte2.d(7): Error: function byte2.foo!byte.foo (byte bar) is not callable using argument types (int)
Oct 12
next sibling parent Daniel Kozak <kozzi11 gmail.com> writes:
Not sure :), I have forgoten byte+byte=int.

On Thu, Oct 12, 2017 at 10:51 PM, kdevel via Digitalmars-d-learn <
digitalmars-d-learn puremagic.com> wrote:

 On Wednesday, 11 October 2017 at 07:09:26 UTC, Daniel Kozak wrote:

 You can avoid cast:

 void foo(T)(T bar){...}

 byte bar = 9;

 foo!byte(bar + byte(1));
Sure? --- void foo(T)(T bar) { } byte bar = 9; void main () { foo!byte(bar + byte(1)); } --- byte2.d(7): Error: function byte2.foo!byte.foo (byte bar) is not callable using argument types (int)
Oct 13
prev sibling parent reply Daniel Kozak <kozzi11 gmail.com> writes:
but it works ok with immutable, so until you really need to change bar you
can use

immutable bar = 9;
foo!byte(bar + 1);

On Fri, Oct 13, 2017 at 9:46 AM, Daniel Kozak <kozzi11 gmail.com> wrote:

 Not sure :), I have forgoten byte+byte=int.

 On Thu, Oct 12, 2017 at 10:51 PM, kdevel via Digitalmars-d-learn <
 digitalmars-d-learn puremagic.com> wrote:

 On Wednesday, 11 October 2017 at 07:09:26 UTC, Daniel Kozak wrote:

 You can avoid cast:

 void foo(T)(T bar){...}

 byte bar = 9;

 foo!byte(bar + byte(1));
Sure? --- void foo(T)(T bar) { } byte bar = 9; void main () { foo!byte(bar + byte(1)); } --- byte2.d(7): Error: function byte2.foo!byte.foo (byte bar) is not callable using argument types (int)
Oct 13
next sibling parent kdevel <kdevel vogtner.de> writes:
On Friday, 13 October 2017 at 07:47:55 UTC, Daniel Kozak wrote:
 but it works ok with immutable, so until you really need to 
 change bar you can use

 immutable bar = 9;
 foo!byte(bar + 1);
As Adam wrote two days ago: 'D doesn't do implicit narrowing conversion... so x + 1 becomes int, but then int to byte requires an explicit cast (unless the compiler can prove the range in that particular expression - this is called "value range propagation").'
Oct 13
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/13/17 3:47 AM, Daniel Kozak wrote:
 but it works ok with immutable, so until you really need to change bar 
 you can use
 
 immutable bar = 9;
 foo!byte(bar + 1);
Right, the reason why your original didn't work is the compiler "forgets" that bar is 9 by the time it gets to the foo call. However, it doesn't forget the value of an immutable.
 
 On Fri, Oct 13, 2017 at 9:46 AM, Daniel Kozak <kozzi11 gmail.com 
 <mailto:kozzi11 gmail.com>> wrote:
 
     Not sure :), I have forgoten byte+byte=int.
One place where the compiler doesn't care is +=: bar += 400; // OK int y = 400; bar += y; // OK -Steve
Oct 13