1

Why can't we compute the cartesian product of two immutable ranges ?

The following code :

import std.stdio;
import std.algorithm;

void main() {

    immutable int[] B = [ 1, 2, 3 ];
    immutable int[] C = [ 4, 5, 6 ];
    auto BC = cartesianProduct(B, C);

    writeln(BC);
}

Throws :

/usr/include/dmd/phobos/std/range.d(4199): Error: cannot modify struct result._ranges_field_1 Repeat!(immutable(int)) with immutable members
/usr/include/dmd/phobos/std/range.d(4503): Error: template instance std.range.Zip!(immutable(int)[], Repeat!(immutable(int))) error instantiating
/usr/include/dmd/phobos/std/algorithm.d(11674):        instantiated from here: zip!(immutable(int)[], Repeat!(immutable(int)))
laurent_test.d(8):        instantiated from here: cartesianProduct!(immutable(int)[], immutable(int)[])
/usr/include/dmd/phobos/std/algorithm.d(11674): Error: template instance std.range.zip!(immutable(int)[], Repeat!(immutable(int))) error instantiating
laurent_test.d(8):        instantiated from here: cartesianProduct!(immutable(int)[], immutable(int)[])
laurent_test.d(8): Error: template instance std.algorithm.cartesianProduct!(immutable(int)[], immutable(int)[]) error instantiating

Futhermore, if the second but the first immutable is removed it works.

According to the phobos implementation, one of the range as to be an inputRange and the other a forwardRange. Why such template constraints ?

matovitch
  • 1,264
  • 11
  • 26
  • Note that what people often intend are mutable arrays of immutable members, e.g. `immutable(int)[]`. `immutable int[]` is equivalent to `immutable(int[])`, which is more restrictive than the first type. Can't say that it applies to your problem, especially since it doesn't fix it. – Sebastian Graf Jan 26 '14 at 22:21

1 Answers1

2

I'm definitely not an expert in D, but I asked a similar question last year and this answer from Jonathan M Davis was excellent.

TL;DR: A range can't be immutable because it would't respect the 4 rules:

R r = void;       // can define a range object
if (r.empty) {}   // can test for empty
r.popFront();     // can invoke popFront()
auto h = r.front; // can get the front of the range

Can you guess the culprint? popFront

Community
  • 1
  • 1
Nil
  • 2,345
  • 1
  • 26
  • 33
  • Indeed, the static assert(isForwardRange!(typeof(B))) failed. – matovitch Jan 26 '14 at 21:22
  • I am sorry I don't accept this answer because I don't understand everything. For example the chain () function works, because it uses the Unqual template. Computing the cartesian product does'nt require popFront isn't it ? Why do we need an input and a forward range ? – matovitch Jan 26 '14 at 21:39
  • 2
    Yeah, I don't think this is the problem here, since even slicing it explicitly, which should remove the top-level immutable, doesn't work. Looks like somewhere in here it is trying to assign to the type internally and that's what is tripping it up; I'm leaning toward it being a latent bug in the implementation but haven't checked the source yet. – Adam D. Ruppe Jan 26 '14 at 22:30