-
Notifications
You must be signed in to change notification settings - Fork 423
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
Remove qualified access from use
statements?
#13978
Comments
One argument in favor of maintaining the current behavior - it allows more ways to resolve conflicts when two used modules provide the same symbol, and is the easiest strategy available. E.g. module M {
var x = 10;
... // Other important symbols
}
module N {
var x = 11;
... // Other important symbols
}
module User {
proc main() {
use M, N;
writeln(x); // This will error due to x being defined in both M and N
}
} Today, there are a few ways to resolve this error. I'm going to list them in order of ease-of-use, to emphasize my point. Strategy 1: Use qualified naming, made available through the use statement itselfThis is by far the easiest option for the user. They know which version they meant to refer to, just add an explicit prefix and you're good to go. If you only utilize the symbol in one place, or use both versions in a small handful of places, this is probably the solution to go with. use M, N;
writeln(M.x); Strategy 2: Exclude x from one of the modulesThis involves splitting the use statement onto two lines, because limitation clauses are only allowed to contain a single module today. This is more appropriate if you find yourself using x over and over again and only need one version - then the cost of adding the prefix to the symbol becomes greater than the cost of splitting the use statement and hiding the version you don't want. // If you wanted N's x
use M except x;
use N;
writeln(x);
// If you wanted M's x
use M;
use N except x;
writeln(x); Strategy 3: Rename one of the versions being brought into scopeThis is more annoying than the previous strategy, but appropriate when you want both versions frequently. Since limitation clauses are only allowed to contain a single module today, and you probably wanted to reference the other symbols in M and N, you need to have one use statement to exclude the version you are renaming, and one use statement to rename it. // If you wanted to rename M's x
use M except x;
use M only x as y;
use N;
writeln(x);
writeln(y);
// If you wanted to rename N's x
use M;
use N except x;
use N only x as y;
writeln(x);
writeln(y); How would this work with imports?Strategies 2 and 3 would obviously still be available, unchanged. Strategy 1 now could also be accomplished with an additional statement: Strategy 1b:use M, N;
import M;
writeln(M.x); The only time strategy 1b would be used if strategy 1 was still available would be if the user wants to be explicit about enabling the qualified naming. I don't know of any instance where a user has written In a world where use statements no longer enable qualified access to a symbol, I would rank this strategy as easier than strategy 3, but similarly as easy as strategy 2 (since it requires both adding a line and modifying the reference that was causing problems). Personally, I suspect this means strategy 2 would be my go-to solution, but that may be biased by living in a world where previously use could accomplish both (so I would probably find having to write an additional import annoying, at least for a little while). ImpactRemoving qualified naming support from use statements removes the easiest strategy for resolving a naming conflict. Other strategies for resolving the conflict are still available, but require more effort on the user's part than the strategy that is getting removed. These strategies are already the better choice when the naming conflict occurs more frequently in the scope, but for a simple single conflict, the strategy that this proposal would remove was preferred. |
@lydia-duncan - yeah, but if we have import statements, I would have expected users to write import M, N;
writeln(M.x); and if the wanted to have unqualified access to symbols within, import * from M, N;
writeln(M.x); (or something along those lines). It's my expectation that we're trying to encourage people to use import and qualified access more. As a result I don't see the change to the ease of use of |
I did anticipate that being a response. However, I don't think it is a fair one - I view the addition of |
I think that makes it sound worse than it is, but really we're arguing about "Which is more useful / less confusing" which is subjective.
Say we are talking about Over on #13979 (and specifically #13979 (comment) ) I think you suggested allowing |
Yeah, I'm definitely more following the re-export case |
Catching up: My preference here is to create a world in which either My proposal for having a pattern for This is obviously a little clunky-looking, making the proposed variants of an |
I agree with Brad that I would prefer a world where If I were to design an For this issue, import M; // qualified access
import M.*; // unqualified access; bring in everything in M, but not M and features like renaming may apply only to one or both of these Closing. |
Should
use
statements enable qualified access? E.g.Note that there is some support for allowing
use Lib
to allow qualified access within the module containing that statement (so later on inmodule LibUser
in the above example there could be an expression likeLib.someVariable
).Reasons to keep qualified access for
use
:import
existinguse
dReasons to remove qualified access for
use
:use
andimport
to allow for greater control of symbol visibilitypublic use Lib
within M would hide the fact that symbols come fromLib
(soM.Lib
will not be available)public import Lib
within M would exposeLib
withinM
(soM.Lib
will be available)import
public or private controls the scope of the module imported; while making ause
public or private only affects the contents of the moduleuse
d.Forked from #13119 (comment) and #11262 (comment). Also, this topic is the first of the Open Questions from #13831.
Today, Chapel's
use
statement does three things AFAICT:public use
in current scope and current scope is a module declaration, a dependent scope can inherit behaviors 1 and 2 through anotheruse
statementHaving both qualified and unqualified accesses being allowed by one statement causes some unintended problems: #11262, #13925, #13925 (comment)
So it got me thinking, how often would it be that a user actually wants both qualified and unqualified access to a symbol? Rarely. It would be better to separate these behaviors as separate statements.
This proposal is to remove qualified access on
use
statements.Caveat:
use
statements would only do unqualified access, so users that prefer qualified access needimport
statements #13119 #13831 to be implemented before this proposal is accepted.One idiom today is
use only
to allow only qualified access:Under this proposal, these statements effectively become no-ops. This would be a breaking change and the best long-term course is to introduce a compiler error to recommend using
import
instead.(It could be a warning, but I don't see how warnings that allow no-op behaviors are useful when the user is likely coming from outdated information or is confused, so their code will likely break later anyway.)
The text was updated successfully, but these errors were encountered: