-
Notifications
You must be signed in to change notification settings - Fork 83
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 implicit import behavior of 'use' #402
base: main
Are you sure you want to change the base?
Conversation
I'm a bit concerned about this creating a lot more complexity for toolchains in the long run. With the current behavior, exposing an interface as part of a world is simple, with the complex parts being handled in a single place, and not being a concern for most kinds of tools. With this change, all tools that want to emit worlds now have to understand all the dependencies, and all the details of how those are handled. And, if I'm not missing something, all that to finally get to a result that is exactly the same as what would happen with the current behavior: you can't use interface |
What we see in practice today is that WIT packages tend to define little |
That is exactly the scenario that worries me: forcing developers to fill in information manually that we can, and currently do, derive automatically. I could easily see reactions along the lines of "all I wanted to do is make use of this function—why does that require more than I guess another question to ask: is there precedent for this kind of behavior? In the context of programming languages it seems unusual, but maybe it's more established for IDLs? |
A smaller change that would still address most of the confusion would be to require explicit imports only where an exported interface depends on that imported interface. Or even incrementaler: only require the explicit import if an export depends on it and it is not already transitively imported. |
@lann That's not a bad idea, and perhaps at the very least we should do something like that. That being said in revisiting this old design choice recently based on @lann's and others helpful feedback, there are a few new reasons that have come to mind for why EIBTI when it comes to worlds:
|
Personally I'd lean towards @lann's suggestion. I feel that strikes a good balance between authorship, understandability, and readability. For fully elaborating a world it's pretty trivial to do with a tool and what I would hope is that for the cases of auditing or documentation or similar that it would be reasonable to assume a tool is between the reader and the WIT itself. For example online registries could fully elaborate all worlds and locally auditing could be based on the output of |
Thinking about @lann proposal again, I worry that it introduces a new set of rules that WIT authors need so that they can understand the corner cases where validation fails (e.g., "why do I have to add an explicit import in this case and not other cases?"). In contrast, with the always-explicit rule, the rule is trivial to state and fix when you encounter it (the validation error message can tell the whole story). Again, given how WIT-based workflows are developing, it doesn't seem like we need to be optimizing for speed of manual authoring of WIT vs. reading of WIT, the latter of which I think very much benefits from seeing all imports laid out plainly (without needing to run a special tool to elaborate). I may be wrong, but removing implicit imports is also a conservative choice, one that we could later relax. And because WIT worlds could end up serving a useful security-related purpose, I think it's important that we take this seriously. |
Having been bit by this a couple of times, I’m sympathetic to both sides of the argument for and against implicit imported types. I appreciate the discussion here.
Expanding on @lann’s comment—what if we lean harder into implicit imports, and:
Related to this (the general topic of WIT not being able to fully express concepts expressible in WAT), I think we should upstream the imported/exported direction of an interface, function, and type into the |
For me the high-order bit here is solving the problem of today it's relatively easy to write something that looks like it works when in fact it means something different and doesn't work. Completely solving this I think will require I think it's also worth considering what we want the "final end state" to look like and if that's Overall what I would expect from a change like this is no one will really remember the exact rules here and will instead let themselves be guided by tooling. In that sense the error message for a missing import is going to be required to basically generate something suitable for copy/paste into a If we want to change the balance of readability/writability of @ydnar one of the implicit assumptions I think you're making is that we have a robust system in place to deliver such warnings to users. Currently though the WIT tooling is very spread out across tooling ecosystems and we didn't originally rely on such a warning system being in place so I think it would be quite difficult to retroactively add that. For example we could pretty easily handle this via the Overall I like the idea of doing something with a warning that users can opt-in to being an error, but I don't think we're at a spot with the tooling and integration of WIT to make such a warning feasible. I do think there's a case to be made to develop such infrastructure/frameworks to make changes like this easier in the future, but that's also further beyond the scope of just the change here unfortunately. |
@alexcrichton thanks for the feedback. In your mind, what is the concrete proposal now? FWIW, I was thinking about having the warning logic live in |
My thinking of what the proposal would be hasn't changed, it's the same as what was mentioned above:
which is targeted at solving the confusing nature of this world: interface a {
resource r;
}
world w {
export a;
use a.{r};
foo: func() -> r;
} The world
Agreed! My point is that this is not sufficient. The
I'm by no means saying this can't be done, I'm instead pointing out "just add it to |
Sorry for the slow reply! (#405 stole all my mental cycles and this required a bit more thought.) Ok, so even though I'm still rather uncomfortable with implicit imports, I do appreciate that, given all the other things in flight, it's probably a good idea to come up with a minimally-impacting fix in the short-term that addresses the flagrant sources of confusion. As for what the precise rule is, I actually prefer @lann's "even more incrementaler" option:
Another way to summarize this option would be: exports never inject implicit imports (only imports can). And the simple rationale is that with exports there's an ambiguity (between injecting an import or export), but with imports there's no such ambiguity. A familiar example that is allowed today and would be continued to be allowed with this more-permissive option is: interface handler {
use types.{request, response, error-code};
handle: func(request) -> result<response, error-code>;
}
world proxy {
import handler;
export handler;
} With the @lann's first option that @alexcrichton quoted above, I think this world would fail validation because The
as "ambiguous" (an ambiguity that is only resolvable once we add How do those two rules sound? Happy to update the PR if that sounds good. |
That all makes sense to me yeah, and I'd be on board with that plan. My rough idea for a transition/migration would be the same as what we did for semicolons where |
Great! Updated this PR to match. PTAL |
Currently, this
world
is valid:and implicitly contains an import of
a
due to theuse
ofa
insideb
. This causes some confusion, especially in the case of exports (which also implicitly add imports foruse
s in exported interfaces, which is often what you actually want, but it's surprising when it's not).This PR removes this implicit-import behavior and instead simply requires a
use
d interface name to have already been imported or exported. So, e.g., to be valid,w
would have to be rewritten:A concrete consequence of this change is that wasi:http/imports would require the addition of
import types;
.This change would complement #308 in helping to clarify and better support advanced (virtualization) cases where a world imports and exports the same interface. This PR contains a NOTE about the remaining ambiguous case that requires #308 to address.
To help P2 WITs transition, perhaps the current WIT tooling could maintain the current implicit-import behavior, but issue a deprecation warning and then at some later date we could turn the warning into an error.
Thoughts?