Skip to content

[Breaking Change Request] Declare return types of Uint8List #36900

Closed
@tvolkert

Description

Current state

The following methods all return Uint8List, yet they are only declared to return List<int>:

  • Utf8Codec.encode()
  • BytesBuilder.takeBytes()
  • BytesBuilder.toBytes()
  • File.readAsBytes()
  • File.readAsBytesSync()
  • RandomAccessFile.read()
  • RandomAccessFile.readSync()
  • Uint8List.sublist()

Relatedly, the following sublist() methods return sublists of the same type as
the source list, yet they only declare that they return the more generic type (e.g. List<int>, List<float>, or List<double>):

  • Int8List
  • Uint8ClampedList
  • Int16List
  • Uint16List
  • Int32List
  • Uint32List
  • Int64List
  • Uint64List
  • Float32List
  • Float64List
  • Float32x4List
  • Int32x4List
  • Float64x2List

Intended change

This issues proposes to update the API of the aforementioned methods to declare the return value of the more specific return type (e.g. Uint8List rather than List<int>).

Rationale

  1. Better type safety

    Callers would like to statically prove that you can obtain a ByteBuffer from the result of these API calls.

  2. The current API/implementation combo encourages bad practices.

    There are two dangers with an API saying it returns List<int> and always returning Uint8List:

    1. People do roundabout things to guarantee that the result is a Uint8List (such as defensively wrapping the result in a Uint8List), which causes unnecessary overhead.
    2. People start to depend on the result being a Uint8List and automatically performing a contravariant cast (which is already happening in Flutter and elsewhere) -- and if anyone new implements the interface and returns something other than a Uint8List, code breaks.
  3. To match the documentation

    Utf8Encoder and Base64Decoder.convert, for instance, already document that they return Uint8List.

See also:

Expected impact

On callers

Callers of these APIs will not be impacted at all since the new return types are subtypes of the existing return types (and moreover, the return values will be the exact same values).

On implementations of the interfaces

Libraries that are implementing the following interfaces will be broken because they will no longer be implementing the interface:

  • Utf8Encoder
  • BytesBuilder
  • File
  • RandomAccessFile
  • Int8List
  • Uint8List
  • Uint8ClampedList
  • Int16List
  • Uint16List
  • Int32List
  • Uint32List
  • Int64List
  • Uint64List
  • Float32List
  • Float64List
  • Float32x4List
  • Int32x4List
  • Float64x2List

This includes (but is not limited to) some well-known packages, such as package:typed_data and package:file.

Steps for mitigation

For known affected packages, the plan will be to issue patch releases to those packages that tighten the SDK constraints to declare that the current version of the package is not compatible with an SDK version greater than the current dev version. Then, once the change lands, we'll update the affected packages to implement the new API and loosen their SDK constraints once again.

Metadata

Assignees

Labels

area-sdkUse area-sdk for general purpose SDK issues (packaging, distribution, …).breaking-change-requestThis tracks requests for feedback on breaking changes

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions