Skip to content

Empty Top Types. #2756

Closed
Closed
@modulovalue

Description

@modulovalue

Consider the following:

void foo<T>(T a) {
  // ...
}

This code contains a top level function foo with a single type parameter T. It might look like T doesn't have any behavior at all, but T is implicitly declared to extend Object?. Any value of type T comes with everything that comes with Object e.g. equality, hashCode, an identity, runtimeType and much much more.

It could be argued that this is bad, but for purposes of practicality this seems to be a very good trade-off and I'm not arguing against that. However, I'd like to be able to specify and have the type checker statically prove that T does not need to be anything as capable as Object is.

This idea of a type not being an Object could seem to make no sense because everything in Dart is an Object. However, if we think of foo as a specification and not as a program, T is simply overspecified. None of its Object capabilities are being used in foo. They are redundant and not necessary.

Also, any reader of foo must for themselves first prove that e.g. the equality/hashCode/runtimeType/toString/... of a is used/unused before he can assume that to be a fact when reasoning about foo. An empty top type would make cases where that is needed much less painful.

What I'd like to be able to do is something like the following:

void foo<T extends Top>(T a) {
  // ...
}

where Top is e.g.

// dart:core

// Top is not an Object.
abstract class Top {}

class Object implements Top {
  /// ...
  external bool operator ==(Object other);
/// ...

i.e. bound T to a Type that has no methods or other properties and is not an Object.


One interesting consequence of that is that it would mean that T could not be used as a key in Maps and could not be the value of Sets. Unfortunately, I think that Lists could also not contain values of type Top because they need equality for e.g. Iterable.contains. But I claim that that is not a bad thing, but a useful feature. We would just need to be explicit about using Lists or Maps with T by e.g. injecting the construction of a List with T and using that instead.

void foo<T extends Top>(
  T a,
  List<T> Function() list,
) {
  final newList = list();
  newList.add(a);
  // ...
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    requestRequests to resolve a particular developer problem

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions