Using records across multiple modules generates error

Why does this Chapel code

module test {
    record dummy_R {
        var a: int(64);

        proc init(): void {
            this.a = 0;
        }
    }
}

module modify {
    use test;

    proc change (const ref rec: dummy_R, val: int(64)): void {
        rec.a = val;
    }
}

use test;
use modify;

proc main (args: [] string): void {
    var test_rec: dummy_R;
    writeln("Before: ", test_rec.a);
    change(test_rec, 5);
    writeln("After: ", test_rec.a);
}

gives me the following error?

record-ref.chpl:14: In function 'change':
record-ref.chpl:14: error: 'dummy_R' undeclared (first use this function)

I'm new to Chapel and would appreciate help from experienced Chapel developers/users.

1 Like

Hi,

I'm not an experienced user, but trying your code on my machine (with Chapel-2.5) gives this error message (here, "rectest1.chpl" is my filename):

rectest1.chpl:11: In module 'modify':
rectest1.chpl:12: error: cannot find module or enum named 'test'
rectest1.chpl:1: note: a module named 'test' is defined here
rectest1.chpl:1: note: however, a full path or an explicit relative use is 
required for modules that are not at the root level
rectest1.chpl:12: note: For non-root-level modules, please specify the full 
path to the module or use a relative import e.g. 'import this.M' or
'import super.M'

So I changed this line

use test;

to

use super.test;
// or, use rectest1.test;

then the above error went away. However, I get two new errors (one for const ref and another for void for main()). So I also changed the code as follows, then it compiled and seems to give the expected result. (However, I am not sure why void for main() gives an error here. Possibly for some internal reasons...?)

module test {
    record dummy_R {
        var a: int(64);

        proc init(): void {
            this.a = 0;
        }
    }
}

module modify {
    // use test;
    use super.test;
    // use rectest1.test;

    // proc change (const ref rec: dummy_R, val: int(64)): void {
    proc change (ref rec: dummy_R, val: int(64)): void {
        rec.a = val;
    }
}

use test;
use modify;

// proc main(args: [] string): void {
proc main(args: [] string) {
    var test_rec: dummy_R;
    writeln("Before: ", test_rec.a);
    change(test_rec, 5);
    writeln("After: ", test_rec.a);
}
1 Like

@tbzy Thanks a lot for doing these extensive tests. Now, this strengthens my belief that it is either a bug in the compiler or some expected but non-intuitive compiler behavior.
@bradcray Maybe you can comment more on this.

Hi @dutta-alankar and @tbzy

The module structure created by the original code is as follows due to the presence of top-level code in the file that is not contained within a module declaration:

module record-ref {
  module test { … }
  module modify { … }
  use test, modify;
  proc main() { … }
}

Or, using more of a tree-like structure, we have a top-level module named record-ref (based on the filename) that contains two sub-modules, test and modify:

record-ref
-> test
-> modify

This nested module structure may or may not be intended. Often what users really want is something more like:

module test { … }
module modify { … }
module Main {
  use test, modify;
  proc main() { … }
}

which yields more of a flat module structure:

test
modify
Main

Reading the code, my expectation was that the error would be like the one @tbzy reported—that test would not be found in the use statement within module modify. However, when I tried it, I happened to put it in a directory that had a file named test.chpl, and the compiler decided that I was asking it to use that file and the test module that it defined. Removing test.chpl from my directory resulted in the same behavior as @tbzy.

Chapel's scoping rules say that a sub-module (modify in this case) cannot refer to a sibling sub-module without going through the parent's scope as @tbzy suggests in:

use super.test;
// or, use rectest1.test;

So that is expected behavior. If the nested modules were all flattened and each was a top-level module, simply using use test; would work.

The error about assigning to rec since it's const is correct—a const, const ref, or const in record cannot be modified, so a ref argument should be used there instead.

The complaint about main returning void is less familiar to me, but I believe the cause is that we expect main to return an int status value, if anything: main() Functions — Chapel Documentation 2.5 That said, this error message could definitely be clarified to make that more evident, and opening an issue about that would be fair game.

Note that, stylistically, we typically omit the return types of procedures that don't return anything rather than explicitly declaring them to return void.

So I think there are no bugs here, but the potential to improve the error message for main procedures declared to return void (or possibly any non-int values?)

-Brad

2 Likes