Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use statement replaces all symbols in current scope? #12744

Closed
BryantLam opened this issue Mar 28, 2019 · 1 comment
Closed

use statement replaces all symbols in current scope? #12744

BryantLam opened this issue Mar 28, 2019 · 1 comment

Comments

@BryantLam
Copy link

BryantLam commented Mar 28, 2019

Related #6872 #11262 #12734 #10021 #9985

Summary of Problem

The following code behaves weirdly, but is correct based on the defined Language Specification.

module M {
  var x = "M";
  class C {
    proc postinit() { writeln("M"); }
  }
}

var x = "g";
class C {
  proc postinit() { writeln("g"); }
}

proc main() {
  writeln(x);
  var c1 = new owned C();
  
  use M; // <-- This use looks backwards in time!
  writeln(x);
  var c2 = new owned C();

  // Expected: g, g, M, M
}
# chpl version 1.19.0
M
M
M
M

From the Language Specification, 11.11:

The names that are imported by a use statement are inserted in to a new scope that immediately encloses the scope ... . This implies that the position of the use statement within a scope has no effect on [that scope's] behavior.

From Brad's comment in #9985:

I acknowledge that we depart from other languages in this respect. By design, Chapel set out to be a language in which declaration order doesn't matter ... .

I understand the principle of Brad's comment, but this code is weird because the use statement is able to replace symbols that chronologically occurred before the use statement in the procedure. If the enclosing scope of the use statement was a module definition, class definition, or some other scope where declaration order didn't matter, then this would be less of an issue, but inside a scope that exhibits a notion of time, it doesn't feel correct even if the behavior is.

Possible solutions:

  1. Do nothing. This is only an issue if enough people think it is. My opinion is that this is definitely an issue for procedures.
  2. Emit a compiler warning if a use statement is not at the beginning of a procedure's scope.
  3. Forbid use statements that are not at the beginning of a procedure's scope.
  4. Allow use statements in procedures to chronologically observe the procedure's order of visibility (i.e., change the behavior to match my Expected results).

Edit: I don't know if 3 is possible if useing a module and then doing a bunch of dynamic casts that could depend on said module. The interplay of compile-time symbol visibility vs. runtime dynamic casting might be the breaking point?

@bradcray
Copy link
Member

I believe this is as intended, though I agree that there's a learning curve here. While there are aspects of procedures that respect time (e.g., the order in which their statements are executed), there are aspects that are independent of time, specifically declarations. For example, given this code (Try it online):

module M {
  var x = 42;
  proc foo() {
    writeln(x);
    var x = "hello";
    writeln(x);
  }
}

it may appear (based on C-like languages, e.g.) that foo() should write out 42 and then "hello" but because Chapel treats declarations as applying to the whole scope (even in procedures), the original writeln(x) is also referring to the declaration of x and so is illegal (since the local scope's x hasn't been declared and initialized yet), and the compiler flags it as such. Similarly, procedures nested within procedures can be called whether they appear before or after the call to the procedure (try it online):

proc foo() {
  proc bar() { writeln("In bar"); }

  bar();  // OK
}

proc baz() {
  bar();  // also OK

  proc bar() { writeln("In bar"); }
}

I believe use statements are consistent in this way as well: Because they are defining symbols they affect the entire scope that they're within independent of statement order.

Though there's admittedly a learning curve here, I have to say I really like this consistency in Chapel, both from a user's and an implementer's point of view (i.e., unlike some choices we've made, I haven't spent a lot of time second-guessing it). I suspect there is more we could do though to help users get surprised by this, for example, in the way of compiler warnings, overload sets (#12635), and/or adding more of a Python-like use-nothing-by-default import in contrast to Chapel's use-everything-by-default use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants