Replies: 6 comments 1 reply
-
I think I prefer ABS too. In addition to considerations above it's easier to reason about when reading code. |
Beta Was this translation helpful? Give feedback.
-
This is where we're probably think of it differently. The plan was eventually that modules can be installed from the external repository, imagine:
And then So this spec fixes conflicts of user modules with stdlib modules. But we will have the same problem once we start installing third-party modules/packages/extensions (or users can start doing that without us, because module can be just a folder in the So since we introduce nested namespaces I think it's better to think how to force (like Rust) or to encourage users (like Python) to use a single top-level name for all their schema. |
Beta Was this translation helpful? Give feedback.
-
A few examples for ABS:
So in summary, in most cases, you have to write absolute names, except when:
Since these two probably cover the majority of all names people are gonna use, I vote for ABS. |
Beta Was this translation helpful? Give feedback.
-
And a suggestion for ABS: could we shorten keyword This is a keyword that will be used to shorten things like I see the consistency with |
Beta Was this translation helpful? Give feedback.
-
I like ABS. Am I remembering correctly that there was talk of allowing developers to import modules created by other developers? If so, this is a case where I think search could get confusing: when you have modules imported you're not 100% familiar with that might be hijacking your path before it gets to where you think it should be in your schema. |
Beta Was this translation helpful? Give feedback.
-
also, for tooling like a language server, using ABS will make autocomplete and go to definition straightforward |
Beta Was this translation helpful? Give feedback.
-
Rationale
pg
andfts
modules in 3.0 to support pg-specific indexes and full-text-search. We'd rather not collide with any existing user module names, so it would be nice to stick them instd::pg
andstd::fts
instead. (And then potentially move everything else likemath
in there too.) I don't think it is mandatory that we put them instd
, but this is one of the major impetuses for "why now" for nested modules.Some proposals
I present two variants of nested modules.
In both variants, I will use "qualified name" to mean any name that
has a :: in it, and unqualified to mean a name without a :: in it.
Always (mostly) absolute (ABS)
In this proposal, a qualified path refers to either a fully qualified
name or to something under
std::
, unless it begins with the keywordmodule
in which case it refers to something under the current module.(We might also want to have a way to refer to the parent module, like
rust's
super
. I don't see any existing reserved keyword that would workwell, but we could do something in dunders, or something symbolic like
..
?)The name resolution algorithm is then:
For
module
-prefixed qualified namesmodule::<modules>::<name>
:<cur_module>::<modules>::<name>
For qualified names
<first>::<rest>::<name>
:<first>
exists, then the nameis
<first>::<rest>::<name>
.std::<first>::<rest>::<name>
Note that we check for the existence of the leading module name, not
the full object name. A top-level module named
pg
would shadowstd::pg
, not overlay with it.For unqualified names
<name>
:<cur_module>::<name>
exists, that is the namestd::<name>
So the main thing here is that the current module affects resolution
for unqualified names, but not for qualified ones (unless they ask
for it).
Scope Searching (SEARCH)
In this proposal, we search up through our scope. Paths prefixed with are absolute paths.
For
::
-prefixed absolute paths:For qualified names
<first>::<rest>::<name>
:then each prefix of the current module descending by length,
then the toplevel, then
std
.So for example, if the current module is
foo::bar::baz
,the search path is
[foo::bar::baz, foo::bar, foo:, <toplevel>, std]
<mod>
in the search path, if<mod>::<first>
exists, then the name is
<mod>::<first>::<rest>::<name>
.Note that like in "always absolute", we check for the existence of the
leading module name.
For unqualified names
<name>
:<mod>
in the search path, if<mod>::<name>
exists, then that is our name.
Other options?
One other option is to do SEARCH but omitting the prefixes from the search path,
so it is just
[<current_module>, <toplevel>, std]
.Another theoretically possible option in the design space is that paths are always
rooted at the current module, and you must do
::whatever
to refer to an absolute path.This is basically what rust does (with
crate::
as the prefix to get an absolute path).This is not backward compatible at all, though, so we can't do it.
Analysis
SEARCH is more full-featured, and can express many names more
concisely than ABS can. On the flip side, it is substantially more
complex and has much more room for surprises where the meaning of a
name can change when something new is introduced earlier along the
search path.
My biggest concern with SEARCH, though, is with normalization.
Currently we normalize all names that go into anything schema
related into qualified names. These qualified names appear in
generated migrations, in the output of DESCRIBE, in schema
introspection fields, and in error messages.
The safest thing to do would be to always normalize everything
into an absolute path with leading
::
s: User becomes::default::User
. This means that any normalized path could bemoved to any module and not change its meaning.
The downside is that this makes migrations and describe output much
noisier, and raises questions about how far to go with this: should
the official object names in the schema start with
::
? Should typeerror messages start with
::
? It is likely to be possible to manageto omit the
::
in some situations, but I think it would end up beingfiddly and very case-by-case.
Another approach for SEARCH normalization is to omit the leading
::
on normalized names. This can be justified by the observationthat we don't actually need to interpret normalized names in
arbitrary current modules. Migrations get run in the
default
module,and so if we ban submodules of
default
, then one of these normalizednames will always be equivalent to an absolute name (when the current
module is default). There's not really a good reason to have submodules
of
default
anyway, so this isn't a huge loss.This approach I think would work and it would avoid the ugliness
and noisiness, but if feels pretty fragile.
With ABS, on the other hand, what a non-
module
qualified name meansdoes not depend on the current module. While a qualified name isn't
always absolute (because of the
std
search), a normalized namealways will be.
I really don't want to put a
::
turd in front of every name everywhere,so my preference ordering here is ABS, SEARCH-with-fragile-normalization,
SEARCH-with-proper-normalization, even though SEARCH-with-fragile-normalization
is kind of an abomination.
Beta Was this translation helpful? Give feedback.
All reactions