-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
[breaking change] Make utf8.encode()
/ Utf8Codec.encode()
return more precise Uint8List
return type
#52801
Comments
This is a follow up on #36900 which intended to make that change, but ended up changing (I do not remember the reason for not changing |
Very LGTM, been asking for this for years :-) |
Ditto. Super useful change. |
To avoid analyzer warnings when `utf8.encode()` will return the more precise `Uint8List` type, we use `const Utf8Encoder().convert()` which already returns `Uint8List` See dart-lang/sdk#52801
To avoid analyzer warnings when utf8.encode() will return the more precise Uint8List type, we use const Utf8Encoder().convert() which already returns Uint8List See dart-lang/sdk#52801
To avoid analyzer warnings when utf8.encode() will return the more precise Uint8List type, we use const Utf8Encoder().convert() which already returns Uint8List See dart-lang/sdk#52801
Do we have an idea of how many instances will require this mitigation? For internal developers, I assume the fixes will be driven by the Dart team? |
The issue with inference - which will make your code compile & run differently seems very rare - I have seen 2 cases so far. What is more common is that code performs an explicit downcast via My plan would be to handle those 2 issues preemptively in g3, dart sdk & flutter related repos before landing the actual change. |
SGTM and LGTM. |
) To avoid analyzer warnings when utf8.encode() will return the more precise Uint8List type, we use const Utf8Encoder().convert() which already returns Uint8List See dart-lang/sdk#52801
lgtm |
To avoid analyzer warnings when `utf8.encode()` will return the more precise `Uint8List` type, we use `const Utf8Encoder().convert()` which already returns `Uint8List` See dart-lang/sdk#52801
A breaking change (see [0]) will make `utf8.encode()` return the more precise `Uint8List` type (instead of the current `List<int>`). In rare circumstances this can lead to changes in behavior, mainly when code relies on type inference, a different type got inferred and the code dependend on the type not being inferred a more precise type. Here we explicitly use `Stream<List<int>>` instead of relying on type inference (which would infer `Stream<Uint8List>` in some cases after [0]). This is necessary as the stream transformer APIs cannot work with subtypes. Example of code that fails at runtime: ``` import 'dart:typed_data'; import 'dart:convert'; void main() { Stream<Uint8List> stream = Stream.fromIterable([]); Stream<List<int>> stream2 = stream; stream2.transform(utf8.decoder); // ^^^ Will throw due to Utf8Decoder not being subtype of // StreamTransformer<Uint8List, String>. } ``` [0] dart-lang/sdk#52801
A breaking change (see [0]) will make `utf8.encode()` return the more precise `Uint8List` type (instead of the current `List<int>`). In rare circumstances this can lead to changes in behavior, mainly when code relies on type inference, a different type got inferred and the code dependend on the type not being inferred a more precise type. Here we explicitly use `Stream<List<int>>` instead of relying on type inference (which would infer `Stream<Uint8List>` in some cases after [0]). This is necessary as the stream transformer APIs cannot work with subtypes. Example of code that fails at runtime: ``` import 'dart:typed_data'; import 'dart:convert'; void main() { Stream<Uint8List> stream = Stream.fromIterable([]); Stream<List<int>> stream2 = stream; stream2.transform(utf8.decoder); // ^^^ Will throw due to Utf8Decoder not being subtype of // StreamTransformer<Uint8List, String>. } ``` [0] dart-lang/sdk#52801 Co-authored-by: Natalie Weizenbaum <nweiz@google.com>
Right now `utf8.encode()` has a static return type of `List<int>` due to extending `Encoding` (which extends `Codec<String, List<int>>`). We cannot easily change `Encoding` to extend `Codec<String, Uint8List>` because that would also change `utf8.decode()` to require `Uint8List` which would be a breaking change. So instead we override `utf8.encode()` to have more precise return type. Some parts of our SDK are run using the checked-in SDK, so it cannot rely on the changed return type yet (until checked-in SDK is rolled). So we use `const Utf8Encoder().convert()` as a temporary change, as that already has `Uint8List` return type. Issue #52801 TEST=ci CoreLibraryReviewExempt: More precise return type for existing API Change-Id: I2861d1f0eb3d292d8e3ec8437c0d441a2d2bd193 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/254903 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com>
The breaking change has landed now. |
The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. [0] dart-lang/sdk#52801
The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` Uint8List bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` Uint8List bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.length); ``` a shorter hand for that is: ``` Uint8List bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` Uint8List bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` Uint8List bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.length); ``` a shorter hand for that is: ``` Uint8List bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` Uint8List bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` Uint8List bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.length); ``` a shorter hand for that is: ``` Uint8List bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
…ter#43335) To avoid analyzer warnings when utf8.encode() will return the more precise Uint8List type, we use const Utf8Encoder().convert() which already returns Uint8List See dart-lang/sdk#52801
…ter#43675) The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` Uint8List bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` Uint8List bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.length); ``` a shorter hand for that is: ``` Uint8List bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
…ter#43675) The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` Uint8List bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` Uint8List bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.length); ``` a shorter hand for that is: ``` Uint8List bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` TypedData bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` TypedData bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.lengthInBytes); ``` a shorter hand for that is: ``` TypedData bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
) The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` TypedData bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` TypedData bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.lengthInBytes); ``` a shorter hand for that is: ``` TypedData bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. As the checked-in SDK has been rolled to include [0] we can now rely on the better return type. [0] #52801 TEST=ci CoreLibraryReviewExempt: Minor cleanup. Change-Id: I2c0144023e03b2c265582d83a7fb9469b02f1570 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313563 Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Ben Konyi <bkonyi@google.com>
…ter#130567) The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` TypedData bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` TypedData bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.lengthInBytes); ``` a shorter hand for that is: ``` TypedData bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
…ter#130567) The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` TypedData bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` TypedData bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.lengthInBytes); ``` a shorter hand for that is: ``` TypedData bytes; ByteData.sublistView(bytes); ``` [0] dart-lang/sdk#52801
While the entire utf8 converter has been switched to Uint8List the type annotation still remains List<int> for this release. Adding the downcast as this behavior is what we need. A future dart release should also change the type annotations triggering a linter rule. see: dart-lang/sdk#52801 Signed-off-by: Nikolas Rimikis <rimikis.nikolas@gmail.com>
While the entire utf8 converter has been switched to Uint8List the type annotation still remains List<int> for this release. Adding the downcast as this behavior is what we need. A future dart release should also change the type annotations triggering a linter rule. see: dart-lang/sdk#52801 Signed-off-by: Nikolas Rimikis <rimikis.nikolas@gmail.com>
…inter to ignore the unnecessary cast. This is to allow us to support dart versions both before and after 3.2.0, specifically for this breaking change dart-lang/sdk#52801 which was introduced in dart 3.2.0 - see https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md
Change Intent
Make
Utf8Codec.encode()
return aUint8List
instead of aList<int>
.Justification
This change will to allow compilers to better optimize code which is accessing the bytes. It also allows being explicit about the guarantees we make: We already guarantee to return a
Uint8List
but it's not visible in the return type. Some users then do explicit downcasts viautf8.encode(...) as Uint8List
, others pass aroundList<int>
which can result in inefficient code.Impact
The impact will be more precision in static types and smaller code size / higher performance is some cases. It may break existing code if such code is relying on type inference to infer
List<int>
and would fail if it would now inferUint8List
.Mitigation
Explicitly pass
List<int>
as type arguments in places where the automatically inferredUint8List
type is incorrect.The text was updated successfully, but these errors were encountered: