www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A range analysis question

reply "bearophile" <bearophileHUGS lycos.com> writes:
Do you know why the assignment to 'item' is accepted in the first 
case and refused in the second?


ubyte generate1(s...)() {
     ubyte[10] result;
     foreach (immutable i, ref item; result)
         item = s[0][0] << 4;
     return result[0];
}

ubyte generate2(s...)() {
     ubyte[10] result;
     foreach (immutable i, ref item; result)
         item = s[0][i % 3] << 4; // line 11
     return result[0];
}

void main() {
     enum ubyte[16] data = [1, 2, 3, 4];
     auto g1 = generate1!data;
     auto g2 = generate2!data;
}


dmd gives:

test.d(11): Error: cannot implicitly convert expression 
(cast(int)[cast(ubyte)1u, cast(ubyte)2u, cast(ubyte)3u, 
cast(ubyte)4u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, 
cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, 
cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, 
cast(ubyte)0u][i % 3u] << 4) of type int to ubyte


Bye and thank you,
bearophile
Jul 10 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/10/2013 03:08 PM, bearophile wrote:

 Do you know why the assignment to 'item' is accepted in the first case
 and refused in the second?


 ubyte generate1(s...)() {
      ubyte[10] result;
      foreach (immutable i, ref item; result)
          item = s[0][0] << 4;
s[0][0] is known to be int 1 at compile time. It is also known that (1 << 4) can fit in a ubyte by value range propagation. dmd is being helpful. Change the code so that the result does not fit a ubyte you will get the same error as in line 11. a) Shift by 8 instead of 4 b) Change the value in main to something like 42
      return result[0];
 }

 ubyte generate2(s...)() {
      ubyte[10] result;
      foreach (immutable i, ref item; result)
          item = s[0][i % 3] << 4; // line 11
That foreach is a runtime foreach because it is applied on 'result' as opposed to the type tuple 's'. Apparently the compiler does not do that kind of code analysis.
      return result[0];
 }

 void main() {
      enum ubyte[16] data = [1, 2, 3, 4];
      auto g1 = generate1!data;
      auto g2 = generate2!data;
 }


 dmd gives:

 test.d(11): Error: cannot implicitly convert expression
 (cast(int)[cast(ubyte)1u, cast(ubyte)2u, cast(ubyte)3u, cast(ubyte)4u,
 cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u,
 cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u,
 cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u][i % 3u] <<
 4) of type int to ubyte


 Bye and thank you,
 bearophile
Ali
Jul 10 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

 Change the code so that the result does not fit a ubyte you 
 will get the same error as in line 11.
The result is supposed to fit in an ubyte because the input is supposed to be made of nibbles. (I have tried to add asserts or tests, but they don't change the situation, so I have omitted them here).
 That foreach is a runtime foreach because it is applied on 
 'result' as opposed to the type tuple 's'. Apparently the 
 compiler does not do that kind of code analysis.
Right, but is it right to ask for such analysis to be performed? Bye, bearophile
Jul 10 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/10/2013 04:10 PM, bearophile wrote:

 Ali Çehreli:

 Change the code so that the result does not fit a ubyte you will get
 the same error as in line 11.
The result is supposed to fit in an ubyte because the input is supposed to be made of nibbles.
Not in either of the two cases that I have given: a) (1 << 8) would not fit a ubyte b) (42 << 4) would not fit a ubyte Of course we are reminded again that even if 1 and 42 are ubytes, the result of the << operator is int. So you first expression (1 << 4) is an int which happens to fit a ubyte and that line compiles.
 (I have tried to add asserts or tests, but they
 don't change the situation, so I have omitted them here).


 That foreach is a runtime foreach because it is applied on 'result' as
 opposed to the type tuple 's'. Apparently the compiler does not do
 that kind of code analysis.
Right, but is it right to ask for such analysis to be performed?
That would be great but there are many other cases where the compiler does not do anything like that. Here, it would have to decide similar to "even though this is a runtime foreach, I know at compile time that 'result' is a fixed-length array so 'i' is between 0 and 10. I also have this compile-time tuple template parameters. Now let me see whether running that code would produce values that would fit the 'result's type ubyte." I don't think we are there yet. :)
 Bye,
 bearophile
Ali
Jul 10 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

 That would be great but there are many other cases where the 
 compiler does not do anything like that. Here, it would have to 
 decide similar to "even though this is a runtime foreach, I 
 know at compile time that 'result' is a fixed-length array so 
 'i' is between 0 and 10. I also have this compile-time tuple 
 template parameters. Now let me see whether running that code 
 would produce values that would fit the 'result's type ubyte."

 I don't think we are there yet. :)
Adding a bit more static analysis to D will help making D a bit more modern language. Having something like "liquid types" is very good, but I think that even much more limited capabilities are enough to avoid avoid some casts and bugs. Recently I have added a related (simple) enhancement request, perhaps it's implementable: http://d.puremagic.com/issues/show_bug.cgi?id=10594 Bye, bearophile
Jul 10 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

 I don't think we are there yet. :)
Thinking some more about this topic I have created a small test example: uint i = 100; void main(in string[] args) { auto j = args.length; ubyte x1 = (i ^^ 2) % 256; // OK ubyte x2 = (i ^^ 3) % 256; // OK ubyte[] arr = [(i ^^ 2) % 256, (i ^^ 3) % 256]; // OK! ubyte y = [(i ^^ 2) % 256, (i ^^ 3) % 256][j]; // Error } The lines with x1 and x2 are accepted, because the range analysis is able to infer those are in-range assignments. While the assignment of y is refused, despite all the contents of the array can be inferred as castable to ubyte, as shown in assignment of arr. I think this (the line with y) is worth an enhancement request. Bye, bearophile
Jul 11 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
 I think this (the line with y) is worth an enhancement request.
http://d.puremagic.com/issues/show_bug.cgi?id=10615 Bye, bearophile
Jul 11 2013