digitalmars.D.learn - Foreach with byte problems
- Andrej Mitrovic (27/27) Feb 25 2011 So I'd like to print all values storable in a byte in hex representation...
- Steven Schveighoffer (8/35) Feb 25 2011 foreach(int index; byte.min..byte.max + 1)
- Andrej Mitrovic (22/22) Feb 25 2011 Maybe it's best to let D do type infering for me. This works ok:
- Steven Schveighoffer (8/30) Feb 25 2011 IFTI is interpreting the element type of iota to byte.
- Andrej Mitrovic (4/5) Feb 25 2011 Cool. I've almost used +1-1, LOL!
- Steven Schveighoffer (4/10) Feb 25 2011 No code is generated to add 0, but it does affect the type.
- Andrej Mitrovic (5/5) Feb 25 2011 Can this be simplified?:
- Steven Schveighoffer (10/15) Feb 25 2011 This is a good puzzle. You may have to do something with map and castin...
- spir (7/33) Feb 25 2011 lol! One more source of fun in using half-open intervals :-)
- Jonathan M Davis (9/62) Feb 25 2011 In the general case, having the first element of an interval be inclusiv...
- Andrej Mitrovic (6/10) Feb 25 2011 I do agree it's the right thing to do, and I wouldn't want to change it.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (23/37) Feb 25 2011 I've seen the same "problem" with enums.
So I'd like to print all values storable in a byte in hex representation: import std.stdio; void main() { int counter; foreach (byte index; byte.min..byte.max) { if (!(counter % 4)) writeln(); counter++; } } If you run this, you'll realize that it doesn't print the final 0x7F. This is because in a foreach range literal (is that the correct term?), the left side is inclusive, but the right side isn't. Hence this will run the foreach from 0 to 9: foreach (index; 0..10) { } So I figured I'd just add a +1 at the end, but then I get an error: foreach (byte index; byte.min..byte.max+1) { } Error: cannot implicitly convert expression (128) of type int to byte. Of course 128 can't fit in a byte. But how am I supposed to print out the last value if the right hand side of a range literal is non-inclusive? This behavior is kind of odd, don't you think? byte.max is 127, but due to the way foreach works, the last value assigned to index is 126. If I was allowed to add +1 for RHS, the last value stored to index would be 127 due to the non-inclusive right side, which is completely legal. Yet DMD complains that I'm trying to store 128 to index. I guess DMD first checks if the value on the RHS of the range literal can fit to a byte before it cuts one off due to the way range literals work. So how do I work around this?
Feb 25 2011
On Fri, 25 Feb 2011 13:52:53 -0500, Andrej Mitrovic <none none.none> wrote:So I'd like to print all values storable in a byte in hex representation: import std.stdio; void main() { int counter; foreach (byte index; byte.min..byte.max) { if (!(counter % 4)) writeln(); counter++; } } If you run this, you'll realize that it doesn't print the final 0x7F. This is because in a foreach range literal (is that the correct term?), the left side is inclusive, but the right side isn't. Hence this will run the foreach from 0 to 9: foreach (index; 0..10) { } So I figured I'd just add a +1 at the end, but then I get an error: foreach (byte index; byte.min..byte.max+1) { } Error: cannot implicitly convert expression (128) of type int to byte. Of course 128 can't fit in a byte. But how am I supposed to print out the last value if the right hand side of a range literal is non-inclusive?foreach(int index; byte.min..byte.max + 1) The truth is, you don't want to use byte to represent your comparisons, because byte.max + 1 isn't a valid byte. And instead of counter, you can use a formula instead: if((index - byte.min) % 4 == 0) writeln(); -Steve
Feb 25 2011
Maybe it's best to let D do type infering for me. This works ok: foreach (index; byte.min..byte.max+1) { if((index - byte.min) % 4 == 0) writeln(); } I'm fine with that. Now, what's wrong with this code: auto foo = iota(byte.min, byte.max-1); // ok // foo = [0, 1, .., 124, 125] auto bar = iota(byte.min, byte.max); // fails // Errors: // D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\range.d(3868): Error: cannot implicitly convert expression (cast(int)pastLast - 1) of type int to byte // D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\range.d(3873): Error: cannot implicitly convert expression (cast(int)pastLast + 1) of type int to byte // D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\range.d(3890): Error: cannot implicitly convert expression (cast(uint)cast(int)this.pastLast - this.step) of type uint to byte
Feb 25 2011
On Fri, 25 Feb 2011 14:15:52 -0500, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:Maybe it's best to let D do type infering for me. This works ok: foreach (index; byte.min..byte.max+1) { if((index - byte.min) % 4 == 0) writeln(); } I'm fine with that. Now, what's wrong with this code: auto foo = iota(byte.min, byte.max-1); // ok // foo = [0, 1, .., 124, 125] auto bar = iota(byte.min, byte.max); // fails // Errors: // D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\range.d(3868): Error: cannot implicitly convert expression (cast(int)pastLast - 1) of type int to byte // D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\range.d(3873): Error: cannot implicitly convert expression (cast(int)pastLast + 1) of type int to byte // D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\range.d(3890): Error: cannot implicitly convert expression (cast(uint)cast(int)this.pastLast - this.step) of type uint to byteIFTI is interpreting the element type of iota to byte. You need to either explicitly instantiate iota (don't recommend this) or cast one of your args to int. auto bar = iota(cast(int)byte.min, byte.max); a dirty trick you could do is add 0, which should promote the arg to int. -Steve
Feb 25 2011
On 2/25/11, Steven Schveighoffer <schveiguy yahoo.com> wrote:a dirty trick you could do is add 0, which should promote the arg to int.Cool. I've almost used +1-1, LOL! Well, I thought DMD would simply ignore +0 (dead code elimination?), but apparently this is a cool shorthand for casting literals? Nice.
Feb 25 2011
On Fri, 25 Feb 2011 14:51:18 -0500, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:On 2/25/11, Steven Schveighoffer <schveiguy yahoo.com> wrote:No code is generated to add 0, but it does affect the type. -Stevea dirty trick you could do is add 0, which should promote the arg to int.Cool. I've almost used +1-1, LOL! Well, I thought DMD would simply ignore +0 (dead code elimination?), but apparently this is a cool shorthand for casting literals? Nice.
Feb 25 2011
Can this be simplified?: byte[] arr = to!(byte[])(array(iota(byte.min, byte.max+1))); The +1 turns byte.max into an int that can store 128. So when I call array on an iota, I'll get back an int[] of [-128, ..., 127]. And I have to convert that to a byte[].
Feb 25 2011
On Fri, 25 Feb 2011 14:34:35 -0500, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:Can this be simplified?: byte[] arr = to!(byte[])(array(iota(byte.min, byte.max+1))); The +1 turns byte.max into an int that can store 128. So when I call array on an iota, I'll get back an int[] of [-128, ..., 127]. And I have to convert that to a byte[].This is a good puzzle. You may have to do something with map and casting, but I don't see how it can be done with iota without a cast. The right thing to do would be this: for(byte i = -127; i < byte.max + 1; i++) arr ~= i; which does everything as a byte, but does the comparisons as ints. But I don't know how to make iota do this. -Steve
Feb 25 2011
On 02/25/2011 07:52 PM, Andrej Mitrovic wrote:So I'd like to print all values storable in a byte in hex representation: import std.stdio; void main() { int counter; foreach (byte index; byte.min..byte.max) { if (!(counter % 4)) writeln(); counter++; } } If you run this, you'll realize that it doesn't print the final 0x7F. This is because in a foreach range literal (is that the correct term?), the left side is inclusive, but the right side isn't. Hence this will run the foreach from 0 to 9: foreach (index; 0..10) { } So I figured I'd just add a +1 at the end, but then I get an error: foreach (byte index; byte.min..byte.max+1) { } Error: cannot implicitly convert expression (128) of type int to byte. Of course 128 can't fit in a byte. But how am I supposed to print out the last value if the right hand side of a range literal is non-inclusive? This behavior is kind of odd, don't you think? byte.max is 127, but due to the way foreach works, the last value assigned to index is 126. If I was allowed to add +1 for RHS, the last value stored to index would be 127 due to the non-inclusive right side, which is completely legal. Yet DMD complains that I'm trying to store 128 to index. I guess DMD first checks if the value on the RHS of the range literal can fit to a byte before it cuts one off due to the way range literals work. So how do I work around this?lol! One more source of fun in using half-open intervals :-) Denis -- _________________ vita es estrany spir.wikidot.com
Feb 25 2011
On Friday, February 25, 2011 11:37:23 spir wrote:On 02/25/2011 07:52 PM, Andrej Mitrovic wrote:In the general case, having the first element of an interval be inclusive and the last one exclusive is perfect. That's how it works with iterators in C++. That's essentially how it works with array indices, since they start with 0 and their length is one greater than the last index. It's just plain nice and makes checking end conditions cleaner. However, it is true that in this particular case, it's annoying. Still, in the general case, I do believe that it's definitely the right behavior. - Jonathan M DavisSo I'd like to print all values storable in a byte in hex representation: import std.stdio; void main() { int counter; foreach (byte index; byte.min..byte.max) { if (!(counter % 4)) writeln(); counter++; } } If you run this, you'll realize that it doesn't print the final 0x7F. This is because in a foreach range literal (is that the correct term?), the left side is inclusive, but the right side isn't. Hence this will run the foreach from 0 to 9: foreach (index; 0..10) { } So I figured I'd just add a +1 at the end, but then I get an error: foreach (byte index; byte.min..byte.max+1) { } Error: cannot implicitly convert expression (128) of type int to byte. Of course 128 can't fit in a byte. But how am I supposed to print out the last value if the right hand side of a range literal is non-inclusive? This behavior is kind of odd, don't you think? byte.max is 127, but due to the way foreach works, the last value assigned to index is 126. If I was allowed to add +1 for RHS, the last value stored to index would be 127 due to the non-inclusive right side, which is completely legal. Yet DMD complains that I'm trying to store 128 to index. I guess DMD first checks if the value on the RHS of the range literal can fit to a byte before it cuts one off due to the way range literals work. So how do I work around this?lol! One more source of fun in using half-open intervals :-)
Feb 25 2011
On 2/25/11, Jonathan M Davis <jmdavisProg gmx.com> wrote:However, it is true that in this particular case, it's annoying. Still, in the general case, I do believe that it's definitely the right behavior. - Jonathan M DavisI do agree it's the right thing to do, and I wouldn't want to change it. But I'd like the compiler to be smart in this case and see that there's no way 128 will ever be stored into a byte. It's not some crucial piece of code that I need working. I just ran into it by accident really.
Feb 25 2011
On 02/25/2011 10:52 AM, Andrej Mitrovic wrote:So I'd like to print all values storable in a byte in hex representation: import std.stdio; void main() { int counter; foreach (byte index; byte.min..byte.max) { if (!(counter % 4)) writeln(); counter++; } } If you run this, you'll realize that it doesn't print the final 0x7F. This is because in a foreach range literal (is that the correct term?), the left side is inclusive, but the right side isn't.I've seen the same "problem" with enums. import std.stdio; enum E { x, y, z } void main() { foreach (e; E.min .. E.max) { writeln(e); } } The value 2 is excluded. Of course it's rare to use enums like that in a foreach loop as their values are not always continuous. I found out the better solution before sending this message: foreach (e; __traits(allMembers, E)) { writeln(e); } The difference is, the type of 'e' is string above. Finally, the following produces integer values: foreach (e; __traits(allMembers, E)) { writeln(to!E(e)); } Ok, good... :) Ali
Feb 25 2011