-
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
Constructing an object of a derived type #741
Comments
In open discussion, we are leaning towards option 2b, and are looking for a better name than |
Expanding on option 2b: We are considering
Methods defined on |
We decided
We have not picked a replacement yet, though. Other spellings that have been brought up: |
Just so folks can see what the option 2b looks like with the direction the syntax is converging:
And then we have the list from @josh11b's comment for keywords that could be used instead of |
Other keyword ideas from a discussion I had with @KateGregory:
Ideas that seem at least plausible enough to the two of us to poll and get feedback on:
I'm going work on conjuring a poll of some kind here.... |
My memory at least of the concerns around some of the options:
|
Do we expect to also use this type variant as the type of the base class during destruction? I think that would make sense, especially given the limits it applies to virtual function calls and expectations about the type's partially-constructed nature. If so, I think that we should discard any names based on initialization or construction. |
Here is a variation on 2b for your consideration, which I will call "2b sugar", which starts with "2b" and adds: There is an alternate introducer
The return type in a The
In extensible classes where both overloads of the name will be generated, the first overload will be defined to return the result of calling the second (prepending If the constructor is declared public (the default), the first version (if present) will be public and the second version (if present) will be protected. Otherwise both versions will have whatever access the constructor is declared with. In this way, users only need to identify which functions are constructors, and don't need to concern themselves with where they should use an alternate type, nor be tempted to declare both public and protected versions of the constructor to make a nicer API for the class. We could additionally provide a way to declare constructors that are not class members. |
So the above example would be rewritten to:
|
I think there's an interesting tradeoff here. The injected parameter and rewriting of calls to add a corresponding argument is a little more magical than I'd prefer, and I'm concerned that it'll be surprising in some cases:
(where the idea is to create an instance of But on the other hand if we don't have a mechanism like this then we end up requiring extra boilerplate to get the benefit of the base constructor / complete object constructor split for extensible classes. |
Would you prefer marking the calls to other constructors that should be rewritten?
These marks seem like things that the compiler or tooling could identify where they are needed for you. |
It sounds like we are converging on option 2b without sugar. We definitely need an alternate type for constructing abstract base classes, and while we will support them for extensible classes (that is base classes that are not abstract), we will leave it up to the user whether they use that or the regular |
I'd also suggest that the keyword should be |
Chatted with @KateGregory and I think we're all happy with this outcome. ship it! |
Defining how construction works is the main (semantic) blocker to defining inheritance in Carbon that I'm aware of. We'd like to extend the "returned var" approach introduced in #257 to I've previously circulated this Google doc with options. Note that this document predates our current approach of using struct literals rather than tuple literals in construction, I've tried to update the content when copying into this issue.
Option 1: no base values, construct derived values directly
The simplest option is to construct values of type
Derived
directly, specifying values for all fields whether they are defined inBase
orDerived
. Link to option 1Advantages:
Base
that may be abstract, eliminating concerns that pure virtual methods would be called.Disadvantages:
Base
private, including their names.Base
, can end up with twoBase
constructor functions.Option 2: construct derived values from base values
The compiler-supplied constructor of type
Derived
takes a value of typeBase
as its first argument, which is used to initialize all fields defined inBase
. The remaining arguments are for fields defined only inDerived
.Link to option 2
Option 2a: unsound option
Link to option 2a
Option 2b: Type enforcement option
Link to option 2b
There were a few sub-variations proposed. I think the most promising is described at the end of the section, in the paragraph starting with "A second, simpler approach would be to include the space for a virtual table pointer in the
Base.NoVirt
type, so the size and offset ofBase.NoVirt
equalsBase
. "Option 3: use interfaces and mixins instead of abstract base classes
Link to option 3
This is the most radical option, probably outside what we could comfortably adopt.
The text was updated successfully, but these errors were encountered: