static arrays becoming value types

bearophile bearophileHUGS at lycos.com
Mon Oct 19 22:58:41 PDT 2009


Walter Bright:

> The previous behavior for function parameters can be retained by making 
> it a ref parameter:
>     void foo(ref T[3] a)

If I have generic code, like a templated function, that accepts both a dynamic and a static array, the function call will change its performance signature according to the type (if I don't add a "ref" the pass of a dynamic array will be O(1) while passing a fixed-size array will be O(n)).

I can accept your idea (and I can see other people here seem to accept it), but I'd like the function to receive the array by value if the array is small, and by reference if it's large (small and large are defined in terms of true bytes). This can be done automatically by the compiler, but this looks unsafe, because it's bad when the compiler changes the program semantics in an invisible way. So something explicit is better:
void foo(bigref T[3] a)

That syntax means that if (T[3]).sizeof is big enough then it's a ref argument, otherwise it's a value argument.

But I think it's better to be able to somehow define that "bigref" in the standard library:
void foo(Bigref!T[3] a)

Andrei may like something like that. To do that "ref" may need to change its nature a little, becoming a kind of subtype that the user can define and use. I am ignorant about this, maybe T[3].REF can be the type of the reference to T[3], as T[3]* is the type of the pointer to a T[3]. If something like this is possible then that Bigref!() becomes just a template that contains a static if that according to the value of (T[3]).sizeof and some constant threshold value becomes an alias of T[3] or T[3].REF.

Questions:
1) How can I allocate a fixed-size array on the heap?
2) Can such array allocated on the heap be return by "ref" from a function? (Or do I have to return it just by pointer)?
3) How can I implement and use a variable-length struct like this, that sometimes improves the performance of some code?
struct S(T) {
  T cargo;
  int len;
  int[0];
}
(variable-length structs can even grow in both ways, and the pointer that points to them has to point to their middle, to a field that contains two lengths, but such structs are are less common, so they may be ignored in this discussion).
4) LLVM, the backend of LDC, can map small array operations on SSE operations, so it can often perform the sum among two fixed-sized arrays of integers in a single asm instruction ad clock cycle. I'd like D to pass such semantics to the backend. We can discuss this later.

Bye,
bearophile



More information about the Digitalmars-d mailing list