-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Reconsider import library ...
#1457
Comments
I like Python's import syntax.
Being able to rename things as they're imported is important.
|
Go lets you do that to (with a different, Go-like syntax). Handy when you want to import two packages that are both called |
I think the second simply needs to be updated to reflect a change in our plans here. Specifically, this was discussed pretty heavily and a decision that changed the behavior was made in #1136 -- see the next to last comment for I think a good summary. I think the design overview reflects this outcome, but the unqualified name lookup hasn't been updated.
I think the biggest thing I want to emphasize is that this only works for libraries within a package, which are expected to be both very local and part of a fairly uniform namespace. I don't think that has many of the concerns here, but maybe I've misunderstood? Mostly want to make sure we're on the same page about what is actually being considered here. |
Something that I really dislike about C/C++, and what I like that is different in other languages: #include "a.h"
#include "b.h"
Foo f; // Where did this `Foo` name come from? I can't tell. This is a problem. In Python: import a
import b
f = a.Foo() # I can see where the name `Foo` comes from. Good. or from a import Foo
from b import Bar
f = Foo() # I can see where the name `Foo` comes from. Good. For every name I bring into scope with imports, I want to be able to see where that name comes from. This is recognized as bad practice by the Python community: from a import *
from b import *
f = Foo() # Where did this `Foo` name come from? I can't tell. This is a problem. For every name I bring into scope with imports, I want to be able to see where that name comes from. |
I'm not sure whether I have the Carbon syntax right, but...
Can we do it like this?
I want to be able to tell where things came from. If the former remains in Carbon, I would hope that it immediately gets recognized as bad practice, in the same way that |
I definitely understand the desire to have this behavior, but I think it would be quite challenging to get here. I think the first challenge here is that things behave differently (perhaps very differently) depending on where you write the code based on how names are imported. The desire for code to retain the same meaning in different contexts is in tension with having very localized names. I think both of these are valuable, but I think we'll have to choose. The second problem is in the face of templates. While we are supporting templates, we'll want cases where code from I'll also point out that this is actually not the topic of this issue (I think), as the point you're making here comes up even without the same-package |
Yeah, that's exactly the problem I'd like to avoid. Tangentially (possibly), I'd also like to avoid the "Abseil can't name something ERROR (which would otherwise be the perfectly obvious name) because WinGDI.h says Nonetheless, in this Carbon snippet:
I'm willing to let |
I'm still not sure if I understand the Carbon package vs library distinction correctly, but my rough model (based on Go experience) is that Carbon package ~ Go module (the coarser unit of software distribution and versioning) and Carbon library ~ Go package (the finer unit of import), with the extra note that Carbon's "ImageMagick / LibMagick" could be the coarse thing and "JPEG codec" or "PNG codec" could be the fine thing. "The fine thing" is still a coarser concept than C/C++ (where the source code file is the unit of import) or Java (where the class is the unit of import, plus In Go, modules are a build tool or package management concept but entirely invisible to the compiler and language. Go source code always imports individual Go packages and never mentions Go modules. If Kubernetes (or one aspect, k8s.io/client-go) is the Go module, here's an example of importing multiple Go packages from within that Go module, and this (multiple imports) hasn't been painful in practice. There's also a demonstration of locally renaming some Go package names in the link, if you're curious, although if starting the syntax from scratch, I'd put the local name on the right instead. |
I think you roughly have the right model.
The example I've been using is Abseil might be a package in Carbon.
I think we should be relatively close to where C/C++ is here, where it is the "external header file" that is the import unit. This often corresponds to a single file, but also often corresponds to several files, from an implementation file to internal helpers.
It's likely this could also work, but I think the shared top-level namespace that libraries like Abseil use in C++ also works quite well. I pointed out above some of the downsides of needing local renaming, and I think not having the coarse level thing be what carries the unique name would put a lot of pressure on longer names or lots of local renaming. It is a tradeoff, but one that I think we've already seen work reasonably well in C++ (where followed closely), and so it seems reasonable to match that pattern in Carbon. |
By "external header file", do you mean:
|
There might be some confusion about whether you were replying about renaming, the
or replying about dot-dot-dot imports, where, after I import Abseil, I can just refer to a naked Or replying about both. There's also the axis on whether you're replying about all packages or just about the special In case it got lost in the subsequent discussion, my original request is that Carbon programmers must always qualify (it's always Specifically, templates and ADL (Argument Dependent Lookup) should still work with qualified names (e.g. I can say |
Ah, I though I understood ADL but re-reading up on it...
is not the same as
That's C++. In the Carbon world, if I But if |
Ah, I missed that, in all the excitement. That goes a long way to alleviate my concerns. It's closer to the Go model: "local" names are "local to the Go package", not "local to the file". Note though that there are still three levels of granularity:
and "local" in Go means "the bottom 2 out of 3" but IIUC in Carbon means "all 3". |
This. We even expect to have analogs to an "umbrella" library that re-exports things if people desire it, but I think we'd like the default/typical case to be pretty fine grained for better build scaling.
Ah, yes. It's a super important point. =D Without this, much chaos. For any name not local to your package, you're going to have to use its package name as a qualifier.
For names that can be used without a qualifier, yes. But we do plan to have things that are private to a library, and private to a source file for implementation files. Now that this is refined/clarified a bit, is there still a question around reconsidering for the leads here? |
I am still a little confused. I'm not confident that I understand the ADL Specifically, I'm not sure if it matters that, in Carbon, IIUC now, you can't Possibly easier said than done, but if |
I'll step back from focusing on ADL and 'what breaks if we don't have I'll start again. Let me know if I've got this wrong. In Carbon, I can say:
A detail I missed earlier is that the names within become qualified by the package name: it's Whether or not C++ is a special case in Carbon, one reason Carbon does this is that C++ libraries' names weren't chosen with qualification in mind, yet in Carbon we'd like to be import multiple C++ libraries that might refer to each others' names (so we can't just automatically prefix these names with the library name):
Another point is that, for same-Carbon-package imports, it's not that the package name can be omitted, it's that it must be omitted. I had originally thought that the Instead, that syntax is for when another Abseil library wants to import Abseil's synchronization library, but there is no I still feel that the Carbon equivalent of:
is a problem. In abstract terms, I'd still prefer that "when Abseil's time library imports Abseil's synchronization library, there's still some sort of |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry for delay in explicitly following up here...
I don't think so, your summary sounds right to me.
Yeah, I can see the desire for this. But I think there are real tradeoffs here as well, and the current structure ended up feeling like a good balance of the different factors. |
We triage inactive PRs and issues in order to make it easier to find active work. If this issue should remain active or becomes active again, please comment or remove the |
https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/README.md#imports says "The
import library ...
syntax adds all the public top-level names within the given library to the top-level scope of the current file as private names". IIUC this is sort of like Java'simport foo.bar.*
.OTOH, https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/name_lookup.md#unqualified-name-lookup says "Unqualified name lookup in Carbon will always find a file-local result".
IIUC, the two statements are contradictory.
Personally, from my Go experience, I prefer the "Unqualified name lookup" principle: users of
type Stamp
frompackage time
(package in the Go sense) always refer to it by a qualified name:time.Stamp
. Similarly,func Decode
frompackage jpeg
is referred to asjpeg.Decode
, which is clearly distinct frompng.Decode
even though in the source code they're both defined asfunc Decode
.Requiring qualified names means that adding names to a library will not cause any downstream importers (that happen to also use that same name, privately) to stop compiling due to a newly introduced ambiguity.
It also means that IWYU (Include What You Use) tools can work purely on the AST without having to follow imports.
(I'll caveat all of the above that I may be misunderstanding Carbon's package/library distinction and the details of its Name Lookup model).
The text was updated successfully, but these errors were encountered: