Outside array bounds

Timoses timosesu at gmail.com
Sat Jul 7 16:08:03 UTC 2018


On Saturday, 7 July 2018 at 15:25:51 UTC, vino.B wrote:
>
> Hi All,
>
>   If we replace the statement as args[$ -1] the program works 
> are expected, if we apply the same logic in different approach 
> it does not work, in the below code if we command the first 
> block "if (fnID == "ListFilesNames") {} " then the second "if 
> (fnID == "ListFilesSize") {}" works fine, and vice versa but if 
> both the "if" block is un-commented it does not work , rather 
> it passes wrong parameter to the function. Tried change the 
> args as args[$] , args[1], args[2],
>
> Error:
> Test.d(31): Error: function Test.ListFilesSize(string FFs, int 
> Size) is not callable using argument types (string, 
> Array!string)
> VarTest.d(31):        cannot pass argument _param_1 of type 
> Array!string to parameter int Size
> Test.d(42): Error: template instance 
> `Test.process!(Array!string)` error instantiating
>
>
> Code:
[...]
> void process(T ...)(string fnID, T args) {

Throw in a pragma here:

   void process(T ...)(string fnID, T args) {
       pragma(msg, T);
       ...
   }

[...]
> void main() {
> Array!string NameDir, SizeDir;
> NameDir.insert("C:\\Temp\\BACKUP1");
> SizeDir.insert("C:\\Temp\\TEAM1");
> int Size = 1;
> string fnID1 = "ListFilesNames", fnID2 = "ListFilesSize";
> process(fnID1, NameDir); // 1
> process(fnID2, SizeDir, Size); // 2

If you call '// 1' first, then the output would be

(Array!string)
... ERROR

and switch the order:

  process(fnID2, SizeDir, Size);   // 2
  process(fnID1, NameDir);   // 1

Now you'll see from the pragma output:

(Array!string, int)
(Array!string)
... ERROR

So the '// 2' call actually compiled fine.

The compiler complains because the function would try to call 
ListFilesSize(int) with the parameter args[$-1], which in this 
case would be the last element, so Array!string.

`args` is a compile time-construct. In effect you instantiate two 
templates with the following calls:

     process(fnID1, NameDir);  // same as 
process!(Array!string)(fnID1, NameDir)

instantiates the function

     void process(string fnID, (Array!string) args) {
         ...
         // accessing args[$-1] equals accessing args[0] (only one 
element)
         ListFilesSize(FFs, args[$ - 1]);
         // above function will call ListFilesSize(string, 
Array!string).. which does not exist, hence the error
     }

and

     process(fnID2, SizeDir, Size);  // same as 
process!(Array!string, int)(fnID1, NameDir, Size)

instantiates the function

     void process(string fnID, (Array!string, int) args) {
         ...
         // this time args.length == 2
         // hence the call to args[$-1] == args[1] == int
         ListFilesSize(FFs, args[$-1]); // compiles!!! args[$-1] 
fits ListFilesSize signature!


It helps me to think in two domains. There is the "static" CT 
(compile-time) and the RT (run-time) domain. You can vary how CT 
code is laid out with "static" statements (such as "static if" or 
"static foreach", or use aliases. Beware that "static this()" or 
static functions are something different once again).

So you would have to determine _at compile time_ how the 
'process' function should look given it's arguments:

void process(T ...)(T args)
{
     static if (T.length == 1 && is(T[0] == Array!string))
     {
         // 1
     }
     else static if (T.length == 2 && is(T[0] == Array!string) && 
is(T[1] == int))
     {
          // 2
     }
}

So in case above function get's called with only one argument 
which is an Array!string, only the '// 1' part is left for the 
run-time to be executed.

OR you could test if the function compiles

     void process(T ...)(T args)
     {
         static if (is(typeof(ListFilesSize(args[$-1]))))
             ListFilesSize(args[$-1]);
         else
             static assert(false);
     }

Another option would be to use template constraints

     void process(T ...)(T args)
         if (is(typeof(ListFilesSize(args[$-1]))))
     {
         ListFilesSize(args[$-1]);
     }

This is a nice chapter to read (in fact the whole book is a great 
read):
http://ddili.org/ders/d.en/cond_comp.html


More information about the Digitalmars-d-learn mailing list