Allow unqualified name lookup in multiple situations:
Member access defines certain member access behaviors. However, it doesn't cover what happens if an unqualified name lookup occurs within a class, particularly for an out-of-line member function definition, or other situations.
The member access design and information accumulation principle affect this.
This will also work similarly to unqualified lookup within C++.
Allow unqualified name lookup which will use the appropriate scope.
Implicit instance binding to me is not proposed; it is left as an
open question.
This proposal updates the class design to address classes.
interface Vector {
fn Scale[me: Self](v: f64) -> Self;
// Default definition of `Invert` calls `Scale`.
default fn Invert[me: Self]() -> Self;
}
// `Self` is valid here because it's doing unqualified name lookup into
// `Vector`.
default fn Vector.Invert[me: Self]() -> Self {
// `Scale` is valid here because it does unqualified name lookup into
// `Vector`, then an instance binding with `me`.
return me.(Scale)(-1.0);
}
More generally, this should also be true of other scopes used in declarations. In particular, namespaces should also follow the same rule. However, since name lookup has not been fleshed out, this won't make much of an update to it.
An example for namespaces would be:
namespace Foo;
var Foo.a: i32 = 0;
class Foo.B {}
// `B` and `a` are valid here because unqualified name lookup occurs within
// `Foo`.
fn Foo.C(B b) -> i32 {
return a;
}
meIn C++, unqualified name lookup can implicitly do instance binding to this. In
other words, this->Member() and Member() behave similarly inside a method
definition.
In Carbon, the current design hasn't fleshed out whether me would behave
similarly. Most design documentation assumes it will not, but it hasn't been
directly considered in a proposal, and
implicit scoped function parameters
might offer a way to make it work in a language-consistent manner.
This proposal takes no stance on unqualified name lookup resolving me: it is
not intended to change behavior from previous proposals.
Issue #2377 asks
how unqualified lookup should work for impl. The
generics design also doesn't appear to give
syntax for out-of-line definitions of other impls.
We could decide not to support unqualified lookup when defining something that is presented within the top-level scope of the file.
Note this has subtle implications. If Foo.C in the namespace example is
considered to be outside the Foo scope for this purpose, it means the function
would need to look like:
fn Foo.C(Foo.B b) -> i32 {
return Foo.a;
}
It could also mean that, on a class, an inline declaration
fn Foo() -> ClassMember is valid, while an out-of-line definition
fn Class.Foo() -> ClassMember is not, requiring Class.ClassMember.
Advantages:
package.a and package.Foo.a are defined but package.Foo.a is
hidden in code while package.a is easy to find. It's likely that
package.Foo.a would be considered unambiguous for unqualified name
lookup.Disadvantages: