Jump to page: 1 2
Thread overview
Foreach with byte problems
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
spir
Feb 25, 2011
Jonathan M Davis
Feb 25, 2011
Andrej Mitrovic
Feb 25, 2011
Ali Çehreli
February 25, 2011
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();

        writef("%#.2x, ", index);
        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?
February 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();
>        writef("%#.2x, ", index);
>         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
February 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();

        writef("%#.2x, ", index);
    }

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
February 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[].
February 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();
>
>          writef("%#.2x, ", index);
>          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

February 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();
>
>         writef("%#.2x, ", index);
>     }
>
> 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

IFTI 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
February 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
February 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.
February 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:
>> 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.

No code is generated to add 0, but it does affect the type.

-Steve
February 25, 2011
On Friday, February 25, 2011 11:37:23 spir wrote:
> 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();
> > 
> >          writef("%#.2x, ", index);
> >          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 :-)

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 Davis
« First   ‹ Prev
1 2