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

Specify structural equality for `Type` values #34447

Open
eernstg opened this Issue Sep 12, 2018 · 2 comments

Comments

2 participants
@eernstg
Member

eernstg commented Sep 12, 2018

Cf. #34429 (comment), #32782, and similar to the treatment of top types in generalized-void.md, we have precedence for requiring structural equality for "built-in instances" of Type (that is, instances created by platform code such as the implementation of runtimeType in Object, plus instances obtained by evaluation of a type variable).

This issue is concerned with making that semantics a specified rule, and specifying that identical is implementation defined. So even though we may require that T1 == T2 evaluates to true we will not require anything specific about identical(T1, T2), except that the current rules already require canonicalization in some cases.

In particular, it is already specified that 'A simple or qualified identifier denoting a class or type alias that is not qualified by a deferred prefix' is a constant expression; hence, such values must be canonicalized and both T1 == T2 and identical(T1, T2) must yield true when T1 and T2 are such simple or qualified identifiers. For example:

import 'dart:async' as async1;
import 'dart:async' as async2;

main() => print(async1.Future == async2.Future); // Must print 'true'.

Given that Future is a generic class and async1.Future denotes the parameterized type async1.Future<dynamic>, it is implied that the guarantees we already have due to the rules about constant expressions include some parameterized types. However, the current rules do not provide any guarantees about other parameterized types than the ones that we can denote implicitly.

In addition to that, the new rules require instances of Type obtained from execution of platform defined code (such as the implementation of methods in Object like runtimeType, and instances of Type obtained by evaluation of a type variable as an expression) to implement operator == in such a way that Type instances representing types that are structurally equal must yield true. For example:

Type typeOf<X>() => X;

bool mustBeTrue1 = typeOf<List<int>>() == typeOf<List<int>>();
bool mustBeTrue2 = typeOf<List<F2>>() == typeOf<List<F3>>(); // F2,3 defined below.
bool mustBeTrue3 = typeOf<Function(double)>() == typeOf<dynamic Function(double d)>();

// Examples covered by #32782 are included, e.g.,
typedef F2 = void Function(int);
typedef void F3(int);
bool mustBeTrue4 = F2 == F3;

class C<X> {
  Type get typeArgument => X
}

C<C<dynamic>> c = C<C<int>>();
bool mustBeTrue5 = c.runtimeType == C<C<int>>().runtimeType;
bool mustBeTrue6 = c.runtimeType == typeOf<C<C<int>>>();
bool mustBeTrue7 = c.typeArgument == typeOf<C<int>>();

In all cases, when identical(T1, T2) is true, T1 == T2 must be true as well, but the converse is implementation defined. That is, no specific result is required, and each implementation may or may not use canonicalization for any of these cases, and they are free to canonicalize some Type instances and not others, even when they represent the same type, except when they are required by the existing rules about constant expressions to be canonicalized.

@eernstg

This comment has been minimized.

Show comment
Hide comment
@eernstg

eernstg Sep 12, 2018

Member

@lrhn, @leafpetersen, do you agree that we should do this?

Member

eernstg commented Sep 12, 2018

@lrhn, @leafpetersen, do you agree that we should do this?

@lrhn

This comment has been minimized.

Show comment
Hide comment
@lrhn

lrhn Sep 12, 2018

Member

Yes. I believe this is already what should be the truth, even if it might not be everywhere.

We have always worked under the assumption that type objects are equal if they represent the same type (otherwise they are completely useless), and constant types are canonicalized.

Member

lrhn commented Sep 12, 2018

Yes. I believe this is already what should be the truth, even if it might not be everywhere.

We have always worked under the assumption that type objects are equal if they represent the same type (otherwise they are completely useless), and constant types are canonicalized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment