www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - should int/short/byte implicitly cast to dchar/wchar/char?

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
Currently, this works:

void foo(dchar i)
{
}

void main(string[] args)
{
     foo(args.length);
}

Does this make any sense?  When is it useful to be able to call a  
dchar-accepting function with a random integer?

I would say dchar should be settable from an (unsigned) integer literal  
(for those cases where you want to use a specific bit pattern), but from  
any integer or unsigned integer?

Same goes for short to wchar and byte to char, and the unsigned  
equivalents.

What do you think?

There is a bug report related to this:

http://d.puremagic.com/issues/show_bug.cgi?id=5995

-Steve
May 16 2011
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 16 May 2011 13:51:55 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 Currently, this works:

 void foo(dchar i)
 {
 }

 void main(string[] args)
 {
      foo(args.length);
 }

Damn, this originally started out as argc and argv, and I forgot how D accepts arguments, so I switched it to this. Unsigned ints are convertable to dchar, but signed ones are not (except for a couple cases, which doesn't make sense). For example, this fails: dchar c = -1; foo(-1); But this passes: int i = -1; dchar c = i; So clearly there are some inconsistencies that need to be fixed, but the situation is not as bad as I thought it was. -Steve
May 16 2011
parent reply KennyTM~ <kennytm gmail.com> writes:
On May 17, 11 02:25, Steven Schveighoffer wrote:
 On Mon, 16 May 2011 13:51:55 -0400, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 Currently, this works:

 void foo(dchar i)
 {
 }

 void main(string[] args)
 {
 foo(args.length);
 }

Damn, this originally started out as argc and argv, and I forgot how D accepts arguments, so I switched it to this. Unsigned ints are convertable to dchar, but signed ones are not (except for a couple cases, which doesn't make sense). For example, this fails: dchar c = -1; foo(-1);

This fails because the compiler can check in compile-time that 0xffff_ffff is > 0x10_ffff....
 But this passes:

 int i = -1;
 dchar c = i;

....but this cannot. 'dchar' should be treated as lower-rank than 'int' and use value-range propagation on it.
 So clearly there are some inconsistencies that need to be fixed, but the
 situation is not as bad as I thought it was.

 -Steve

May 16 2011
parent KennyTM~ <kennytm gmail.com> writes:
On May 17, 11 03:58, Steven Schveighoffer wrote:
 On Mon, 16 May 2011 15:47:55 -0400, KennyTM~ <kennytm gmail.com> wrote:

 On May 17, 11 02:25, Steven Schveighoffer wrote:
 On Mon, 16 May 2011 13:51:55 -0400, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 Currently, this works:

 void foo(dchar i)
 {
 }

 void main(string[] args)
 {
 foo(args.length);
 }

Damn, this originally started out as argc and argv, and I forgot how D accepts arguments, so I switched it to this. Unsigned ints are convertable to dchar, but signed ones are not (except for a couple cases, which doesn't make sense). For example, this fails: dchar c = -1; foo(-1);

This fails because the compiler can check in compile-time that 0xffff_ffff is > 0x10_ffff....

That is not what the error suggests: Error: cannot implicitly convert expression (-1) of type int to dchar Seems like it's the type that's failing. At the very least, the error message should stress it's the value, not the type, that is the culprit. If I change the literal to 0x10_ffff, indeed it passes, and 0x11_0000 fails. I think this is probably the right behavior, it can be useful to use binary or hex numbers to construct characters.
 But this passes:

 int i = -1;
 dchar c = i;

....but this cannot. 'dchar' should be treated as lower-rank than 'int' and use value-range propagation on it.

I'm not sure what you mean, I think the dchar init statement should fail. I think this is what you are saying, right?

Right.
 Note in the bug report previously referenced, the compiler blindly
 accepts -1 as a dchar argument.

 -Steve

The compiler blindly accepts an 'int' as a 'dchar' argument, not -1. For instance, void main(){ string ret; ret ~= 0x10ffff; // ok ret ~= 0x110000; // Error: cannot append type int to type string int i = 0x110000; ret ~= i; // ok, but should fail at compile time } the issue is also that an 'int' shouldn't be implicitly convertible to a 'dchar'.
May 16 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On 2011-05-16 12:47, KennyTM~ wrote:
 On May 17, 11 02:25, Steven Schveighoffer wrote:
 On Mon, 16 May 2011 13:51:55 -0400, Steven Schveighoffer
 
 <schveiguy yahoo.com> wrote:
 Currently, this works:
 
 void foo(dchar i)
 {
 }
 
 void main(string[] args)
 {
 foo(args.length);
 }

Damn, this originally started out as argc and argv, and I forgot how D accepts arguments, so I switched it to this. Unsigned ints are convertable to dchar, but signed ones are not (except for a couple cases, which doesn't make sense). For example, this fails: dchar c = -1; foo(-1);

This fails because the compiler can check in compile-time that 0xffff_ffff is > 0x10_ffff....
 But this passes:
 
 int i = -1;
 dchar c = i;

....but this cannot. 'dchar' should be treated as lower-rank than 'int' and use value-range propagation on it.

I'd argue that assigning an int to a dchar should fail in all cases where there is no cast and where the compiler cannot use value-range propogation to verify that the value being assigned to the dchar is a valid value for a dchar. So, in the above case, if the compiler fails to do value-range propagation for some reason (which it shouldn't in a case this small), the assignment should be illegal, because there is no cast. And if the compiler manages to do value-range propagation (as it should), then it should still fail, because -1 is not a value value for a dchar. - Jonathan M Davis
May 16 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 16 May 2011 15:47:55 -0400, KennyTM~ <kennytm gmail.com> wrote:

 On May 17, 11 02:25, Steven Schveighoffer wrote:
 On Mon, 16 May 2011 13:51:55 -0400, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 Currently, this works:

 void foo(dchar i)
 {
 }

 void main(string[] args)
 {
 foo(args.length);
 }

Damn, this originally started out as argc and argv, and I forgot how D accepts arguments, so I switched it to this. Unsigned ints are convertable to dchar, but signed ones are not (except for a couple cases, which doesn't make sense). For example, this fails: dchar c = -1; foo(-1);

This fails because the compiler can check in compile-time that 0xffff_ffff is > 0x10_ffff....

That is not what the error suggests: Error: cannot implicitly convert expression (-1) of type int to dchar Seems like it's the type that's failing. At the very least, the error message should stress it's the value, not the type, that is the culprit. If I change the literal to 0x10_ffff, indeed it passes, and 0x11_0000 fails. I think this is probably the right behavior, it can be useful to use binary or hex numbers to construct characters.
 But this passes:

 int i = -1;
 dchar c = i;

....but this cannot. 'dchar' should be treated as lower-rank than 'int' and use value-range propagation on it.

I'm not sure what you mean, I think the dchar init statement should fail. I think this is what you are saying, right? Note in the bug report previously referenced, the compiler blindly accepts -1 as a dchar argument. -Steve
May 16 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 16 May 2011 16:06:34 -0400, KennyTM~ <kennytm gmail.com> wrote:

 The compiler blindly accepts an 'int' as a 'dchar' argument, not -1. For  
 instance,

 void main(){
      string ret;
      ret ~= 0x10ffff;  // ok
      ret ~= 0x110000;  // Error: cannot append type int to type string
      int i = 0x110000;
      ret ~= i;         // ok, but should fail at compile time
 }

 the issue is also that an 'int' shouldn't be implicitly convertible to a  
 'dchar'.

Yes, you are completely right, it seems the compiler isn't inconsistent WRT string appending and calling a normal function, it fails/passes the same way, depending on whether the argument passed is a variable or a literal. So it seems the correct solution is for it to do range propagation, and refuse to compile implicit casts where it results in an invalid dchar (which includes the case where the int could be anything). Sorry for the confusion, I thought I tested one thing, and actually tested another, yada yada... -Steve
May 16 2011
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
news:op.vvk48tn9eav7ka localhost.localdomain...

 What do you think?

Ick! Kill it!
May 16 2011
parent reply Don <nospam nospam.com> writes:
Nick Sabalausky wrote:
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
 news:op.vvk48tn9eav7ka localhost.localdomain...
 (int/short/byte can sometimes implicitly cast to dchar/wchar/char)
 What do you think?

Ick! Kill it!

It's not easy. Simply disallowing it would make code like this illegal: char c = '0' + n;
May 16 2011
next sibling parent KennyTM~ <kennytm gmail.com> writes:
On May 17, 11 12:04, Don wrote:
 Nick Sabalausky wrote:
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
 news:op.vvk48tn9eav7ka localhost.localdomain...
 (int/short/byte can sometimes implicitly cast to dchar/wchar/char)
 What do you think?

Ick! Kill it!

It's not easy. Simply disallowing it would make code like this illegal: char c = '0' + n;

It is already illegal. You cannot implicitly convert an 'int' to 'char' (Error: cannot implicitly convert expression (48 + n) of type int to char).
May 16 2011
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/16/2011 9:09 PM, Jonathan M Davis wrote:
 On 2011-05-16 21:04, Don wrote:
 It's not easy. Simply disallowing it would make code like this illegal:

 char c = '0' + n;

Well, forcing the n to be cast to char or byte would do it, but that _is_ kind of ugly. char c = '0' + cast(char)n; Definitely a good point though.

It's THE reason why such casts are not allowed. Pascal requires such casts, and I always hated it for that. The casts are not only annoying, they can cause bugs when the types of the rest of the expression are changed in maintenance. There isn't any simple answer to mixed integer type arithmetic, although there are many "obvious" answers that have subtly pernicious behavior.
May 16 2011
parent "Nick Sabalausky" <a a.a> writes:
"Walter Bright" <newshound2 digitalmars.com> wrote in message 
news:iqsu2b$1aqs$1 digitalmars.com...
 On 5/16/2011 9:09 PM, Jonathan M Davis wrote:
 On 2011-05-16 21:04, Don wrote:
 It's not easy. Simply disallowing it would make code like this illegal:

 char c = '0' + n;

Well, forcing the n to be cast to char or byte would do it, but that _is_ kind of ugly. char c = '0' + cast(char)n; Definitely a good point though.

It's THE reason why such casts are not allowed. Pascal requires such casts, and I always hated it for that. The casts are not only annoying, they can cause bugs when the types of the rest of the expression are changed in maintenance. There isn't any simple answer to mixed integer type arithmetic, although there are many "obvious" answers that have subtly pernicious behavior.

I was going to suggest the rule: "char + numeric type == char" (and likewise for wchar/dchar), provided that the value range propogation works out, and if it doesn't then you do: char c = cast(char)('0' + n) Is that one of the "obvious" answers that has subtly pernicious behavior? If so, I'm curious what the problem with it is.
May 17 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On 2011-05-16 21:04, Don wrote:
 Nick Sabalausky wrote:
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
 news:op.vvk48tn9eav7ka localhost.localdomain...
 (int/short/byte can sometimes implicitly cast to dchar/wchar/char)
 
 What do you think?

Ick! Kill it!

It's not easy. Simply disallowing it would make code like this illegal: char c = '0' + n;

Well, forcing the n to be cast to char or byte would do it, but that _is_ kind of ugly. char c = '0' + cast(char)n; Definitely a good point though. - Jonathan M Davis
May 16 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 17 May 2011 00:04:07 -0400, Don <nospam nospam.com> wrote:

 Nick Sabalausky wrote:
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message  
 news:op.vvk48tn9eav7ka localhost.localdomain...
 (int/short/byte can sometimes implicitly cast to dchar/wchar/char)
 What do you think?


It's not easy. Simply disallowing it would make code like this illegal: char c = '0' + n;

don't you mean dchar c = '0' + n? And I wouldn't mind if dchar + int => dchar. I also wouldn't mind requiring a cast when range propagation proves the dchar could be invalid. In any case, I think: string s = "hello"; s ~= 123; looks like it should result in: assert(s == "hello123"); Especially anyone coming from any other language. They certainly would not expect it to be "hello{" To me, dchar is the more specialized type, it's like a typedef of uint -- you should be able to implicitly cast to uint/int, but not to dchar. It's kind of like a pointer, you can do this: int n; int* ptr; ptr += n; but you can't do this: ptr = n; -Steve
May 17 2011