-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Summary of issue:
This question is about the C++ interoperability mapping for reference types (T&) versus pointer types (T*), specifically concerning C++'s type system rules for template instantiation and overload resolution.
In C++, T* and T& are distinct types. They resolve differently for function overloads and create different template specializations. Carbon's proposed mapping seems to be based on semantics (like nullability) rather than preserving this fundamental type distinction. For example, C++ T& (non-nullable) and C++ T* _Nonnull map to Carbon T* (non-nullable), while C++ T* (nullable) maps to Carbon T*?.
How will this semantic mapping preserve the type identity required for high-fidelity interop? Specifically, how will Carbon distinguish between an imported C++ template specialization for MyTemplate<Foo*> versus MyTemplate<Foo&>?
Details:
In C++, the distinction between a pointer and a reference is not just syntactic; it is fundamental to the type system.
-
Overload Resolution: A function can be overloaded on pointer vs. reference types. These are unambiguous and distinct function signatures:
void CppFunc(MyType* p);
void CppFunc(MyType& r); -
Template Instantiation: A template specialized on a pointer type is a completely different type from one specialized on a reference type:
template<typename T> class CppTemplate {... };
CppTemplate<MyType*>andCppTemplate<MyType&>are two unique, incompatible types.
Carbon's interoperability goal is to handle C++'s complex features, including templates and operator overloading. However, the current mapping proposals seem to create a conflict:
- C++
MyType&(non-nullable reference) and C++MyType* _Nonnull(non-nullable pointer) map to CarbonMyType*(non-nullable pointer). - C++
MyType*(nullable pointer) maps to CarbonMyType*?(nullable pointer).
This mapping is based on nullability, but it seems to erase the C++ distinction between a pointer and a reference. This raises critical questions for bi-directional interoperability:
-
Importing Templates: When Carbon imports
CppTemplate, how will it represent the difference betweenCpp.CppTemplate(MyType*)(fromCppTemplate<MyType&>) andCpp.CppTemplate(MyType*?)(fromCppTemplate<MyType*>)? Is this the intended mapping? -
Calling Overloads: If Carbon imports the overloaded
CppFuncfrom the example above, what will the Carbon signatures be?- Will
void CppFunc(MyType& r);becomefn CppFunc(r: MyType*)? - Will
void CppFunc(MyType* p);becomefn CppFunc(p: MyType*?)? - If so, how does a Carbon user call the C++
MyType*overload? Do they have to pass aMyType*?value, even if they know their pointer isn't null?
- Will
This seems to break the "seamless" and "unsurprising" mapping goal. We need a clear model for how Carbon's type system will preserve the distinct identities of C++ pointer and reference types to correctly handle template specializations and function overloads.
Any other information that you want to share?
No response