Search code examples
dphobos

Object.Error: Access Violation when printing result of std.algorithm.cartesianProduct


I'm using DMD 2.062 for x86.

module test;    

private enum test1
{
    one,
    two,
    three,
}

private enum test2
{
    one,
    two,
    three,
}

auto ct = cartesianProduct([EnumMembers!test1], [EnumMembers!test2]);

unittest
{
    import std.stdio;
    foreach (n, m; ct)
    {
        writeln(n, " ", m);
    }
}

This program prints out:

one one
two one
three one

Then an access violation error is thrown. Am I using cartesianProduct incorrectly, or is this a bug in the function?


Solution

  • Tiny bit of both, probably. The issue here is that ct is attempted to be evaluated at compile-time and produces result range that is used in run-time. I guess either CTFE or cartesianProduct does not expect such scenario and something bad happens that involves using invalid memory. I think it should have either work, or be a compile-time error, but that won't help you and belongs to bug tracker.

    What does matter here, though is that everything will work if you move ct initialization to unit-test body or static this() module constructor. What you seem to miss is that D does not support initialization of global variables at program start-up. Value assigned to global is always evaluated at compile-time, which often "just works", often results in compile-time error (if initialization is not CTFE-able) and in this case results in weird behavior :)

    What you may want is this code:

    auto Test1Members = [ EnumMembers!test1 ];
    auto Test2Members = [ EnumMembers!test2 ];
    alias CT = typeof(cartesianProduct(Test1Members, Test2Members));
    CT ct;
    
    static this()
    {
        ct = cartesianProduct(Test1Members, Test2Members);
    }
    

    In general, interconnection between compile-time data and run-time data for complex types as arrays or associative arrays is very tricky with current D front-end implementation and requires lot of attention.