-
Notifications
You must be signed in to change notification settings - Fork 213
Should structs and extension structs be tied together? #2361
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
Comments
Initial opinion: I prefer the |
I tend to think that it is unimportant to send a signal to every developer every time they use a zero-cost wrapper, indicating that it's to some extent the same thing as a value class. In other words, I don't think it's very important to share a keyword, even in the case where we do want to share some semantics. That said, we have the separate question about boxing and identity: If we support boxing of an expression whose static type is an extension struct This ensures that the boxed object has the same interface members as the statically resolved members of So that is one area where I think it would be useful to have a connection between the semantics of structs and of extension structs. |
I feel like bundling these two features together does not actually bring us any benefit. I can see some parallels between them - but If we bundle them together then I would expect that one is subset of another or there is a clear shared core, but beyond some syntactic similarities I don't see that here. |
I'm somewhat coming around to this, but only based on the ideas of:
That is, I'm not very comfortable with a world in which there are three unrelated declaration forms in play here, e.g.:
That's a lot of surface area in the language and a lot of cognitive load/complexity for users. |
I agree with this sentiment. I was rotating these two features in my head trying to figure out how they fit together and how things could be decomposed, but so far I was unable to find something that really makes sense. One thing that I thought about is that if extension types on What if we tweaked extension resolution to permit specifying extensions on typedef types (meaning that typedef types are not eagerly substituted, but can participate in things like extension method resolution). In this case: typedef WrappedInt = int;
extension WrappedIntMethods on WrappedInt {
} gives you almost the extension struct? |
What if we treat That means using extension struct Foo<T> on List<T> {
... members ...
} The difference between this and just There is no need to allow Basically, "views" with new syntax. |
Yes, this is a direction we've looked at. My primary objection is that I very firmly believe that the typing and scope resolution that is currently used in extension methods is wrong for views. Specifically:
There are some examples of the differences in resolution in the two approaches here. Given this, it seems misleading to me to build off of extension methods, since the typing is substantially different. There is no reason that I can see that view methods should be typed and resolved differently from class methods, which pushes me to unify them with classes, rather than with extension methods.
I don't know what you mean here.
I'm fairly opposed to this design choice. There some discussion of the choices available here. |
Subtyping can mean a lot of things in object oriented languages, and most of those things are often conflated. In Dart, subtyping has so far meant substitutability, covariant non-coercing assignability, and allowing all valid supertype invocations on the subtype.
None of those are necessary for a "subtyping" relation. The first one is pretty fundamental for OO languages, but you could imagine a language where up-casts were coercive, say, if a three-tuple assigned to a two-tuple type would discard the third value. They could claim that a three-tuple is a subtype of a two-tuple. When I say that "being usable at the supertype, not as the supertype", I'm referring to breaking the third point even more. We can allow an extension struct/view type to be a subtype of its supertype, but still have a completely different set of member signatures when used at the extension struct type, than what the supertype interface has. Basically, it's like viewing the object at the extension struct type only allows the "extension methods" to be called. I say that
because I expect the extension struct to be a zero-cost wrapper. The underlying object is of the on-type. Member resolution at the extension struct type is necessarily static (because a zero-cost wrapper cannot represent the extension struct currently in use, that'd be a cost, so there can be no dynamic dispatch other than what's provided by the underlying object). That does not mean we have to have automatic assignability in either direction, we get to decide that. So, that's what I meant. |
The extension struct proposal here ties together structs and extension structs in two ways: it uses overlapping syntax (the
struct
keyword), and it has a goal that the constructs may be thought of as not adding new functionality, but rather simply subtracting functionality from a more general construct in order to enable new affordances. Sostructs
may be thought of for the most part as restrictions on classes, andextension structs
as restrictions onstructs
. This is not entirely true, since at least as proposed, primary constructors are new syntax, and there are semantic deviations around identity (in the case of structs) and runtime representation in general (in the case of extension structs), but to a first approximation it is true. A disadvantage of this is that it requires finessing around competing priorities: some restrictions we may wish to impose on structs aren't really necessary for extension structs, and vice versa. An alternative approach is to split out the constructs into two or three separate features, breaking the connection, and giving greater flexibility to the design space. In the most general form, we'd split this into three separate features:We could also choose to restrict primary constructors to just data classes and views, to avoid complexities around supporting primary constructors for general classes.
The text was updated successfully, but these errors were encountered: