Jump to page: 1 2
Thread overview
Out of bound problem
Feb 17, 2008
bearophile
Feb 17, 2008
Denton Cockburn
Feb 17, 2008
Neil Vice
Feb 17, 2008
Denton Cockburn
Feb 17, 2008
Christopher Wright
Feb 17, 2008
Sergey Gromov
Feb 17, 2008
bearophile
Feb 17, 2008
Christopher Wright
Feb 17, 2008
bearophile
Feb 18, 2008
Christopher Wright
Feb 18, 2008
Bill Baxter
Feb 18, 2008
Christopher Wright
Feb 18, 2008
Christopher Wright
Feb 18, 2008
Bill Baxter
Feb 18, 2008
Ary Borenszweig
Feb 19, 2008
Bill Baxter
Feb 19, 2008
Christopher Wright
Feb 17, 2008
Sergey Gromov
February 17, 2008
While testing I have found a problem in my code, I have reduced the code to the following lines:

template IsArray(T) {
    const bool IsArray = is(typeof(T.length)) && is(typeof(T.sort)) &&
                         is(typeof(T.reverse)) && is(typeof(T.dup));
}

TA[] foo(TA, TB)(TA[] a, TB b) {
    TA[] result;

    static if (IsArray!(TB)) {
        if (b.length == 0) {
            result = a;
        } else if (b.length == 1) {
            result = foo(a, b[0]);
        }
    }

    return result;
}

void main() {
    foo("test", "");
}


Its output:

bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
bug.d(21): template instance bug.foo!(char,char[0u]) error instantiating

I have found ways to solve this problem, but can someone please explain me what's the problem?

Bye and thank you,
bearophile
February 17, 2008
On Sat, 16 Feb 2008 19:43:54 -0500, bearophile wrote:

> While testing I have found a problem in my code, I have reduced the code to the following lines:
> 
> template IsArray(T) {
>     const bool IsArray = is(typeof(T.length)) && is(typeof(T.sort)) &&
>                          is(typeof(T.reverse)) && is(typeof(T.dup));
> }
> 
> TA[] foo(TA, TB)(TA[] a, TB b) {
>     TA[] result;
> 
>     static if (IsArray!(TB)) {
>         if (b.length == 0) {
>             result = a;
>         } else if (b.length == 1) {
>             result = foo(a, b[0]);
>         }
>     }
> 
>     return result;
> }
> 
> void main() {
>     foo("test", "");
> }
> 
> 
> Its output:
> 
> bug.d(13): Error: array index 0 is out of bounds b[0 .. 0] bug.d(13):
> Error: array index 0 is out of bounds b[0 .. 0] bug.d(13): Error: array
> index 0 is out of bounds b[0 .. 0] bug.d(21): template instance
> bug.foo!(char,char[0u]) error instantiating
> 
> I have found ways to solve this problem, but can someone please explain me what's the problem?
> 
> Bye and thank you,
> bearophile

I tried looking at this.  It's weird (and tripping me out).
I would love to see the explanation of what's going wrong here.
February 17, 2008
"bearophile" <bearophileHUGS@lycos.com> wrote in message news:fp800a$2781$1@digitalmars.com...
> While testing I have found a problem in my code, I have reduced the code to the following lines:
>
> template IsArray(T) {
>    const bool IsArray = is(typeof(T.length)) && is(typeof(T.sort)) &&
>                         is(typeof(T.reverse)) && is(typeof(T.dup));
> }
>
> TA[] foo(TA, TB)(TA[] a, TB b) {
>    TA[] result;
>
>    static if (IsArray!(TB)) {
>        if (b.length == 0) {
>            result = a;
>        } else if (b.length == 1) {
>            result = foo(a, b[0]);
>        }
>    }
>
>    return result;
> }
>
> void main() {
>    foo("test", "");
> }
>
>
> Its output:
>
> bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
> bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
> bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
> bug.d(21): template instance bug.foo!(char,char[0u]) error instantiating
>
> I have found ways to solve this problem, but can someone please explain me what's the problem?
>
> Bye and thank you,
> bearophile

As far as I can tell the cause is that the expression b[0] is being evaluated even if the enclosing if statement hasn't been entered. For example if the line containing b[0] is replaced with a writef() it is never output to the console.

I can only assume that this is a compiler bug.


February 17, 2008
On Sun, 17 Feb 2008 11:37:53 +0900, Neil Vice wrote:

> "bearophile" <bearophileHUGS@lycos.com> wrote in message news:fp800a$2781$1@digitalmars.com...
>> While testing I have found a problem in my code, I have reduced the code to the following lines:
>>
>> template IsArray(T) {
>>    const bool IsArray = is(typeof(T.length)) && is(typeof(T.sort)) &&
>>                         is(typeof(T.reverse)) && is(typeof(T.dup));
>> }
>>
>> TA[] foo(TA, TB)(TA[] a, TB b) {
>>    TA[] result;
>>
>>    static if (IsArray!(TB)) {
>>        if (b.length == 0) {
>>            result = a;
>>        } else if (b.length == 1) {
>>            result = foo(a, b[0]);
>>        }
>>    }
>>
>>    return result;
>> }
>>
>> void main() {
>>    foo("test", "");
>> }
>>
>>
>> Its output:
>>
>> bug.d(13): Error: array index 0 is out of bounds b[0 .. 0] bug.d(13):
>> Error: array index 0 is out of bounds b[0 .. 0] bug.d(13): Error: array
>> index 0 is out of bounds b[0 .. 0] bug.d(21): template instance
>> bug.foo!(char,char[0u]) error instantiating
>>
>> I have found ways to solve this problem, but can someone please explain me what's the problem?
>>
>> Bye and thank you,
>> bearophile
> 
> As far as I can tell the cause is that the expression b[0] is being evaluated even if the enclosing if statement hasn't been entered. For example if the line containing b[0] is replaced with a writef() it is never output to the console.
> 
> I can only assume that this is a compiler bug.

Behaviour exists in DMD 2.010 and GDC 0.25(1.021)

February 17, 2008
bearophile wrote:
> While testing I have found a problem in my code, I have reduced the code to the following lines:
> 
> template IsArray(T) {
>     const bool IsArray = is(typeof(T.length)) && is(typeof(T.sort)) &&
>                          is(typeof(T.reverse)) && is(typeof(T.dup));
> }

...
Y'know, there's a template for this in std.traits and tango.core.Traits.

> TA[] foo(TA, TB)(TA[] a, TB b) {
>     TA[] result;
> 
>     static if (IsArray!(TB)) {
>         if (b.length == 0) {
>             result = a;
>         } else if (b.length == 1) {
>             result = foo(a, b[0]);
>         }
>     }
> 
>     return result;
> }
> 
> void main() {
>     foo("test", "");
> }
> 
> 
> Its output:
> 
> bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
> bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
> bug.d(13): Error: array index 0 is out of bounds b[0 .. 0]
> bug.d(21): template instance bug.foo!(char,char[0u]) error instantiating

Ouch! Constant expansion for the lose!

What's going on is, this is being evaluated at compile time, when you've got a runtime check for length. So it's expanded like this:

if ("".length == 0) {
   // blah
} else if ("".length == 1) {
   result = foo(blah, ""[0]);
}

Then the compiler sees: Array literal! Constant index! Must expand!
Obviously, it can't do that. So it gives an error.

So, you can use a static if, but that'll fail for a dynamic array. Or you can pass in ""[] rather than "". Or you can check if it's a static array, do a 'static if (array.length)' in that case, and in the case of a dynamic array, use a non-static if.

But yeah, it's a bug.

> I have found ways to solve this problem, but can someone please explain me what's the problem?
> 
> Bye and thank you,
> bearophile
February 17, 2008
bearophile <bearophileHUGS@lycos.com> wrote:
> TA[] foo(TA, TB)(TA[] a, TB b) {
>     TA[] result;
> 
>     static if (IsArray!(TB)) {
>         if (b.length == 0) {
>             result = a;
>         } else if (b.length == 1) {
>             result = foo(a, b[0]);
>         }
>     }
> 
>     return result;
> }

It seems to replace the line
result = foo(a, b[0]);
with
result = foo("test", ""[0]);
and then complain that the constant expression ""[0] is wrong.  It's
about distinguishing between static and dynamic arrays which I don't
know how to do.

In your case, adding static if(b.sizeof) should do the trick: only empty static arrays have zero size.

-- 
SnakE
February 17, 2008
Christopher Wright <dhasenan@gmail.com> wrote:
> if ("".length == 0) {
>     // blah
> } else if ("".length == 1) {
>     result = foo(blah, ""[0]);
> }
> 
> Then the compiler sees: Array literal! Constant index! Must expand! Obviously, it can't do that. So it gives an error.
> 
> [...]
> But yeah, it's a bug.

But how the compiler should handle this ?  In trivial case above, the code with error is unreachable.  But as a generic solution, it probably should expand into something like:

if (condition) {
    // blah
} else if (other condition) {
    blah;  // stays here for possible side effects
    // ""[0] is replaced with this at compile time
    throw new ArrayBoundsException();
    // the rest of the block is unreachable, throw away
}

-- 
SnakE
February 17, 2008
Thanks to everybody, in my code I did solve the problem like this:
result = foo(a, b.dup[0]);

But I was curious to know what you think about this situation. Now I know it's probably a compiler bug.


Christopher Wright:
> Y'know, there's a template for this in std.traits and tango.core.Traits.

I don't use Tango (yet). I use always the std lib when possible, I know there's no point in duplicating the std lib. I don't remember the bugs or the problems, but I have found std.traits not enough for similar array purposes, and I have found a bug in the traits of Tango to do that array purposes, so I have created IsArray and IsDynamicArray, you can find them in my d libs:

template IsArray(T) {
    const bool IsArray = is(typeof(T.length)) && is(typeof(T.sort)) &&
                         is(typeof(T.reverse)) && is(typeof(T.dup));
}
template IsDynamicArray(T) {
    const bool IsDynamicArray = is( typeof(T.init[0])[] == T );
}
template IsStaticArray(T) {
    const bool IsStaticArray = IsArray!(T) && (!IsDynamicArray!(T));
}

That IsArray may look a bit like "duck typing at compile time", but that's the only thing that works that I have found. I use similar tools all the time, so I need to have them quite sharp :-)

Bye,
bearophile
February 17, 2008
bearophile wrote:
> Thanks to everybody, in my code I did solve the problem like this:
> result = foo(a, b.dup[0]);
> 
> But I was curious to know what you think about this situation. Now I know it's probably a compiler bug.
> 
> 
> Christopher Wright:
>> Y'know, there's a template for this in std.traits and tango.core.Traits.
> 
> I don't use Tango (yet). I use always the std lib when possible, I know there's no point in duplicating the std lib. I don't remember the bugs or the problems, but I have found std.traits not enough for similar array purposes, and I have found a bug in the traits of Tango to do that array purposes, so I have created IsArray and IsDynamicArray, you can find them in my d libs:

std.traits.isArray/isStaticArray/isDynamic doesn't work? I don't recall seeing such a bug report.

> template IsArray(T) {
>     const bool IsArray = is(typeof(T.length)) && is(typeof(T.sort)) &&
>                          is(typeof(T.reverse)) && is(typeof(T.dup));
> }
> template IsDynamicArray(T) {
>     const bool IsDynamicArray = is( typeof(T.init[0])[] == T );
> }
> template IsStaticArray(T) {
>     const bool IsStaticArray = IsArray!(T) && (!IsDynamicArray!(T));
> }

const bool IsStaticArray(T) {
   const bool IsStaticArray = is(typeof(T[0])) && is(typeof(T[0])[T.sizeof/T[0].sizeof] == T);
}

Then, since IsStaticArray doesn't depend on IsArray, you can change IsArray to return true iff IsStaticArray or IsDynamicArray.

> That IsArray may look a bit like "duck typing at compile time", but that's the only thing that works that I have found.
> I use similar tools all the time, so I need to have them quite sharp :-)
> 
> Bye,
> bearophile
February 17, 2008
Christopher Wright:
> Then, since IsStaticArray doesn't depend on IsArray, you can change IsArray to return true iff IsStaticArray or IsDynamicArray.

You are right, thank you. I'm learning D still.

Bye,
bearophile
« First   ‹ Prev
1 2