Thread overview | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 17, 2008 Out of bound problem | ||||
---|---|---|---|---|
| ||||
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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | "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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to Neil Vice | 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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christopher Wright | 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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christopher Wright | 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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 Re: Out of bound problem | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christopher Wright | 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
|
Copyright © 1999-2021 by the D Language Foundation