Skip to content

Circular module dependencies #226

Open
@cardillan

Description

@cardillan

Mindcode allows circular dependencies among required modules. Example:

File a.mnd:

require "b.mnd";

var a = b + 1;

begin
    println(a);
end;

File b.mnd:

require "a.mnd";

var b = a + 1;

begin
    println(b);
end;

Compiling a.mnd under strict syntax results into a syntax error ("b.mnd:5:9 Variable 'a' is not defined."). However, when compiling a.mnd under relaxed syntax, the following (unoptimized) code is produced

op add *tmp0 :a 1
set .b *tmp0
print .b
print "\n"
op add *tmp1 .b 1
set .a *tmp1
print :a
print "\n"
printflush message1
end
print "Compiled by Mindcode - github.com/cardillan/mindcode"

Note 1: there's a slight problem with the resolution of variable a. When b gets initialized, the a variable gets implicitly created in the main scope. println(a) then resolves a as the main variable, not as the global variable; therefore there's print :a and not print .a in the compiled code. It's perhaps a bit unexpected, but it's part of the circular dependency problem as a whole and will disappear when that gets fixed.

Module dependencies are compiled before the modules they depend on. This approach works great if there are no circular dependencies between modules, as every module is compiled before the modules that depend on it are; however as soon as there are circular dependencies, some modules that are part on the cycle will unavoidably get compiled before the module they depend on (which is the case here).

This is no problem for functions, as functions calls can be resolved before the function code is generated. However, the above example shows this may cause troubles for variables. Obviously there isn't a solution and we want a compile error to be reported even under relaxed syntax.

At this point, I lean towards this solution:

  • Files to be included in a program using the require directive will have to contain the module declaration (which will be introduced in version 3.2).
  • Modules (i.e. source files containing the module declaration) will be automatically compiled using strict syntax. It won't be possible to compile a module under relaxed or mixed syntax. (Support for compiling different modules using different syntax modes will need to be implemented).

This is in line with my intention to provide relaxed syntax only for short scripts, and require strict syntax for more complex projects. Under this solution, both a.mnd and b.mnd will have to be a module and will have to be compiled under strict syntax, at which point the "Variable 'a' is not defined." error occur. (Now, this error message might be improved in this situation, but at least the incorrect code won't compile.)

Note 2: similar problem may affect initialization code and code within function calls. If the value of a in b.mnd is obtained by calling a function in a.mnd, the value of a might be read before it is initialized. I won't be addressing this. Circular dependencies are a bad thing and if a user decides to have them, he needs to figure the resulting problems out. (This is a problem affecting all platforms in some way. For example, Java allows circular dependencies between classes, and a member of a class might get also read before it is initialized when this happens.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions