Skip to content

How to Introduce a Parametric Top Type? #10662

Closed
@odersky

Description

@odersky

We'd like to introduce a parametric top type (call it Top for now) with the following properties:

  • Top is a supertype of Any.
  • Any is the only class directly inheriting from Top.
  • The only member of Top is asInstanceOf
  • To check a scrutinee X against a pattern P, both X and P must be instances of Any.

The question is where Top would replace Any in the rest of the language. There are several choices.

Minimal Solution

Top is just another type. We have to opt in when using it. For instance, we could write

opaque type IArray[+T] <: Top = Array[T]

This would close the hole described in #7314.

This solution is maximally backwards compatible with current Scala. But it has the downside that abstract or opaque types with Top as upper bound are not very useful. They cannot be passed to any regular unbounded type parameter, since such parameters would have upper bound Any.

Intermediate Solution

Opaque types have Top as default upper bound. Type parameters and abstract types stay as they are. This would still be backwards compatible with Scala-2, since opaque types are a new construct. But the problems of usability of opaque types remain.

Maximal Solution

Unbounded abstract types, opaque types, and type parameters have Top as upper bound, instead of Any.
This means

  1. we cannot pattern match on such types anymore
  2. we cannot use the ==, equals, hashCode, or toString defined in Any on such types. On the other hand, we could re-introduce these methods as extension methods for these types, which was not possible before.

This is ultimately the most clear and useful solution, but it poses a lot of problems for migration and interoperability.

  • Migration: Lots of code will break. Think of HashMaps, for instance. We could alleviate some of the breakage by adding an implicit conversion from Top to Any which would warn each time it is inserted. Not sure how much this would help.

  • Interoperability: How should we interpret a Java or Scala-2 unbounded type parameter? If we assume bounds Nothing..Any this would again hamper the usefulness of Scala 3 parametric types. I.e. we could not even do xs.map(f) if xs is of type List[T] and T is unbounded. This looks unacceptable. If we assume bounds Nothing..Top, this means that we accept that the abstraction might be broken in Scala-2 or Java code. This is bad, but better than the alternative. One additional problem is that when reading Scala-2 code we not not even know whether a type parameter is bounded or whether it has explicitly given Nothing..Any bounds. The two are indistinguishable in the pickle format. So we'd have to widen these bounds unconditionally to Nothing..Top.

Questions

  • Is it at all feasible to introduce Top?
  • What is the best solution (or maybe we need a sequence of steps)?
  • What is the migration story?
  • What timeline is realistic for this?

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions