-
Notifications
You must be signed in to change notification settings - Fork 212
Do we need Any
? What's the breakage if Object?
becomes a non-top type?
#3265
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
The feature specification of extension types currently treats |
It's not just extension types which introduce subtypes of top types that neither subtypes of As for The advantage here is then that We'll make sure to declare that all objects are instances of a subtype of There is no distinction between The alternative of saying that the type |
I'm not so worried about type variables with no declared bound: It is specified which type is used as the implicitly declared bound (currently it's In particular, if we introduce
That's what I mean by getting rid of the anomaly. So that's one option.
That's what I mean when I say that we turn None of these options is breaking, because it is still true that all pre-extension-type types are subtypes of
|
That's not what I'm suggesting. I'd still treat Then I'd also add the axiom to the subtype relation that We'd then have four basic top types: So it'd be a distinct type from It doesn't matter whether we change the default bound on type variables, because they have the same subtypes, the same member signatures, and the same member access and usage restrictions (unlike That's also a good argument for not needing two distinct types, which is why we've gotten away with not having And it would indeed not be possible to specify that a type parameter cannot be an extension type. Alternatively, we could just specify a completely abstract and unanchored set of "Dart object default members" which have the names and signatures of the current |
Forgive me, but I'll have to disagree on several points.
Hence,
I don't see the purpose. How should I think it makes sense to say that It also makes sense to say that
It certainly does matter if we consider When you're discussing the pros and cons of two proposals you should qualify statements which are only valid assuming that we're ignoring one of the proposals. Otherwise it doesn't amount to much of a comparison.
Again, we can do that, but having a real interface type ( |
I'm very likely ignoring both and suggesting a third alternative. So let's try again. Let's assume we introduce a nominative
No. I do not believe that can be made to work, or make sense. I do not believe we can design a consistent system where (Or if we do design it, the added complications will far outweigh any gains from having So about:
It's not manageable, at all. That would drive a stake to the hearth of the assumptions of our type system, that a type only has one representation (well, up to alpha equivalence of type parameters, order of named fields/parameters, etc., all those structural differences inside a single kind of type, but we definitely know whether it's structural or nominative, whether it's A rule like:
would have to decide, upon seeing the type Maybe we can go through all our rules and introduce
That is how we treat the type today, it really is the union type What you're asking here is what would happen if The immediate effects would be:
Should you be allowed to declare classes which I don't think it's worth the potentially massive migration. So I reject both ideas, and suggest that if we want a nominative The only real change is that the depth and UP functions now start at About the comments to what I said:
It's treated as
You keep saying "the top type", but Dart doesn't have a single unique top type. It has an infinte number of top types: Currently
I'm not sure what "notational exception" means. It suggets that the type We can probably define that, but our type system is described using algebraic datatype-like terms, where That's probably doable by fixing all occurences of So take Take We can still apply I don't think we'd have problems with our other type functions, because It's actually possible, more than I initially though, that this can work, but we'd have to be very, very careful about not letting a single If the goal is to have a source for the API of |
That's a very nice analysis, @lrhn! I think we're converging. At least, I changed my mind about letting
Sounds good! So This also means that the "least" upper bound algorithm has a uniform structure to work on: No funny exceptions.
Yes, at this point I've been convinced that we can maintain this perspective without creating contradictions. We would then add one more subtype rule: According to the old rules we have for all This yields the following superinterface graph: graph BT;
Null --> Any
Object --> Any
And in addition to the subtype relationships introduced by superinterface relationships we have the following (where everything not involving graph BT;
Any[Any, dynamic, void] --> Object?
Object? --> Any[Any, dynamic, void]
T[any type T] --> Any
So every type We should probably also specify that |
If toString, equals, hashCode and all methods from the Object class are moved to the Any class, will Object become an opaque type? Considering that extension types are a micro-optimization, would a type that allows fields only (a struct) ever exist? In this case, might be better to have an opaque Any type. graph TD;
Any-->dynamic;
Any-->void;
dynamic-->Object/Some;
dynamic-->Null/None;
void-->Object/Some;
void-->Null/None;
Object/Some -->T;
Object/Some -->T?;
Null/None-->T?;
|
What would 'opaque' mean in this context? It usually means something like 'not transparent', but I can't immediately find a way to use that interpretation here.
One notion of opaque types is "types that we can denote, but we cannot recognize what they stand for". For example, an SML structure (a bit like a Dart library) can define types as aliases of other types, and they are opaque in the sense that they are not equal to their definition outside the structure: (* Language: SML *)
structure IntNat = struct
type nat = int; (* This type is opaque *)
val zero = 0;
fun succ x = x + 1;
end
val one: IntNat.nat = IntNat.succ IntNat.zero;
val intOne: int = one; (* Compile-time error: IntNat.nat is not assignable to int *) But I don't think we'll have any consequences which are similar to this notion of opaqueness. I'm not sure about the subtype (or superinterface?) diagram. We certainly don't want |
I mean a marker interface, because it won't have any members. However, Any will be a supertype of Null while Object won't. It's more clear to me now the coexistence usefulness of Any and Object.
I thought void and dynamic could be interfaces (implemented by Object and Null) and Any would be the supertype of everything, but that's not possible I guess. |
I prefer to consider @checkMemberInvocationsDynamically
typedef dynamic = Any;
@dontUseTheValueOfAnExpressionWithThisType
typedef void = Any; // OK, that's a syntax error, but let's pretend. So it might be possible to make them superinterfaces rather than annotated versions of the top type, but it introduces additional expressive power that we would then have to prevent the usage of. We would be able to have instances proving that |
Based on the language team discussions yesterday I'll conclude that (1) |
For future reference, I wanted to leave a pointer to: #2756 That issue claims that having a type that does not have any of the Object members (e.g. toString/==/hashCode...) would be extremely valuable. I still believe that to be the case. I hope that, should the hierarchy ever be "cleaned up", that a type without the implicit Equality (==) / Stringable (toString) / HashCode (hashCode) / RuntimeInfo (noSuchMethod & runtimeType) behaviors will be considered to be included into the hierarchy. |
We currently have some anomalies around the top types: The types
void
anddynamic
are variants of a nameless top type with special static treatment, and we useObject?
as a construct that denotes the "plain" top type.However, we can't really say that
Object?
"declares" operator==
,toString
,hashCode
,runtimeType
, andnoSuchMethod
, which means that it is a matter of weasel words and magic thatNull
has such members as well, and we trust an expression of typeObject?
to be able to dotoString()
etc.We should introduce an explicitly named top type, say
Any
, in order to normalize this part of the language.The question is then: Is
Object?
just a specialized notation forAny
? The difference suddenly matters when we have potentially nullable extension types because they should be subtypes of the top type, but if we make them subtypes ofObject?
and do not say thatObject?
is a special notation that meansAny
then we do say thatObject?
is a supertype of everything which is a subtype ofObject
and everything which is a subtype ofNull
, and then it is highly inconsistent to say "by the way, it's also a direct supertype of some extension types". That's not the way types of the formT?
otherwise work.I'd recommend that we do introduce a plain top type, perhaps named
Any
, and use that to clean up the specification. The default upper bound of a type variable would then beAny
rather thanObject?
, and we probably need to make similar changes in several other locations.Next, how much finicky work do we need to do, and keep doing, in order to maintain that
Object?
andAny
is the same type, no ifs and buts? Is it manageable? Is it useful?Alternatively, what are the pros and cons of saying that the extension types are subtypes of
Any
, but notObject?
? (In other words, we're then saying there is nothing special aboutObject?
, it's treated exactly likeT?
whereT
isObject
.)We would then have the property that potentially nullable extension types cannot be used in a number of locations where developers have explicitly specified the type
Object?
, with the intention that it means the top type. Is that a pro or a con?[Edit] The discussion below gave rise to a proposal that we adopt the following superinterface hierarchy:
In addition to that, the following subtype relationships are proposed (where everything not involving
Any
is a rule that we already have today):@dart-lang/language-team, WDYT?
The text was updated successfully, but these errors were encountered: