carbon-lang
carbon-lang copied to clipboard
CTAD in Carbon?
Doc: https://docs.google.com/document/d/1QwW0KF1OikLYPtr6EWDCw_zSCcts1kvvwijGRwozv8s/
In case we decide we want to take on CTAD-like behavior in Carbon, I'm creating this as a long-term issue so the doc doesn't get lost and is hopefully eventually picked up as a proposal.
class C(T:! type) {
fn Make(t: T) -> Self;
var value: T;
}
// Notice that C is unparameterized in the function name
fn C.Make[T:! type](t: T) -> C(T) {
// Notice C(T) is deduced from the context
return .Make(t);
}
fn Run() -> i32 {
// Notice that C is unparameterized in the variable type specifier
var c: C = .Make(0);
return c.value;
}
Thanks for creating the issue, seems good to have something to track this.
Also gives me a good place to mention a high-level concern I have in this direction -- note, this isn't necessarily something we need to address right away, more something for anyone picking this up to look into.
I think the motivation here could use some strengthening. I think CTAD is one of the C++ features that isn't trivially motivated by interop or migration, as there are other ways of achieving similar or identical results. We could always just require users to provide the class templates of C++ classes even though there are CTAD rules in interop, and during migration we could potentially migrate APIs away from CTAD and towards some other API design.
I see two directions to potentially motivate this further. One would be to work through the ergonomic problems with interop w/o CTAD and build a case that even though it is "only" an ergonomic issue, it will materially make the interop fail to be seamless. I'm somewhat dubious about this being the case, but it is definitely an angle to explore. The second direction is to instead focus on the original motivation for CTAD and explore how to best craft APIs that create instances of class templates and what we want these to look like. The second direction may yield different designs that are more divergent from CTAD, but this is an area where that seems potentially OK if it provides a cleaner design, and then we can look at how interop and migration fit into the picture and whether the divergence poses a problem in practice for either.
Thanks for sharing, @chandlerc!
You say:
The second direction is to instead focus on the original motivation for CTAD and explore how to best craft APIs that create instances of class templates and what we want these to look like.
My personal opinion is that code like the following is super slick!
var c: C = .Make(0);
It has all the information you need (var, c, C, Make and 0) with minimal line noise and no duplication. Compare that to current code where you would write out the following:
var c: C(i32) = C(i32).Make(0);
By specifying the type parameter on both sides, you're duplicating code. In addition, it's in triplicate because the argument 0 could be used to perform the deduction but it isn't unfortunately.
I refer to this as CTAD, because I think it creates a valid migration target for CTAD-using code in C++, but I would argue that anchoring too heavily on CTAD misses the forest for the trees. This set of syntactic sugar changes feels like it stands on its own, in my view. It feels valuable enough to add to Carbon even if CTAD had never been added to C++.
Totally cool if my opinion is outvoted on this. But it is the opinion I currently hold :)
I wonder how the advent of forms might impact this idea. 🤔
Another potential approach: auto (or some other signifier) that lets you omit certain arguments to class types.
class Array(T:! type, N:! i32) {
// stuff
}
var msg: Array(auto, auto) = .Make('w', 'o', 'r', 'l', 'd');
@geoffromer Said in Discord that this mixed-use of auto is perhaps fine (the first being a type, the second being an instance).
@geoffromer Said in Discord that this mixed-use of
autois perhaps fine (the first being a type, the second being an instance).
From a feasibility point of view, that is.