[Breaking Change Request] Declare return types of Uint8List #36900
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
-
Better type safety
Callers would like to statically prove that you can obtain a
ByteBuffer
from the result of these API calls. -
The current API/implementation combo encourages bad practices.
There are two dangers with an API saying it returns
List<int>
and always returningUint8List
:- People do roundabout things to guarantee that the result is a
Uint8List
(such as defensively wrapping the result in aUint8List
), which causes unnecessary overhead. - 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 aUint8List
, code breaks.
- People do roundabout things to guarantee that the result is a
-
To match the documentation
Utf8Encoder
andBase64Decoder.convert
, for instance, already document that they returnUint8List
.
See also:
- Bug BytesBuilder.takeBytes should explicitly provide a Uint8List #27818
- Bug File.readAsBytes should return Uint8List #31547
- Bug Should Base64 decoder have a return type of Uint8List? #31784
- Bug utf8.encode should return Uint8List #35521
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.