-
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 Request] Declare return types of Uint8List #36900
Comments
For better consistency across API, maybe some other methods could be similarly updated?
Main use-case - accessing |
While I support those changes,
The other changes you suggest should be able to be included in this proposal with the same impact. Specifically:
|
A The places you should be concerned about are the ones where the Since streams are entirely covariant, I don't think changing |
Good point - I think I was squinting too hard when I was thinking about the streams cases 😄 |
Just found two more streams: |
There's no reason to change the contravariant case right? The reason to do this is just that we can guarantee that places where we want a Uint8List (which is more efficient than a List of int) we definitely get one. |
@Hixie correct. |
@dgrove @matanlurey for approval. |
I would like to discuss the mitigation strategy more. I don't think there is necessarily anything better that we can do, but the suggested strategy does have shortcomings that should be highlighted.
Releasing a new version with a tightened sdk constraint doesn't prevent users from getting an older version of the package which still has the wider constraint. This leads to a few issues:
There are couple things I can think of to mitigate this, but we can't solve the fundamental problem afaik (at least not without some really ugly pub hacks):
|
Also for posterity the "really ugly pub hacks" would involve either patching the pubspecs of the uploaded versions of these packages (to limit the sdk upper bound) or adding custom logic in the pub client itself to artificially restrict the older versions of these packages. |
Actually, it occurs to me that the affected packages could release new versions now that return the more specific return types, and they'll still be properly implementing the interfaces as currently defined. |
This is LGTM from me. @jakemac53 In general I agree with you, but I don't think it applies to this change, ~mostly, with maybe the only exception being: // Before
var results = [file.readAsBytesSync()];
results.add([0]); // OK
// After
var results = [file.readAsBytesSync()];
results.add([0]); // Runtime error: List<int> is not a type of UInt8List |
I agree this won't affect most consumers code directly, but we need to make sure they fetch a valid version of their dependencies that are affected, which is the part that concerns me. Even if that is a very small number of packages, it sounds like they are fairly core packages (typed_data specifically) that are affected so done wrong this could cause a lot of pain. |
@jakemac53 following on your suggestions, what if we never mucked with the SDK constraints of packages at all, but rather released new versions of the affected packages (that contain the restrictive upper bounds) ASAP without a breaking version bump, so that when the breaking change lands, anyone who's affected should be able to get into a good state by simply running Thoughts? |
This is in preparation for dart-lang/sdk#36900
This is in preparation for dart-lang/sdk#36900
This is in preparation for dart-lang/sdk#36900
Part of the rollout of dart-lang/sdk#36900
So I did a deep dive on all affected packages, and it turns out Here are the rollout implementor changes so far:
|
In preparation for dart-lang/sdk#36900
In preparation for dart-lang/sdk#36900
Ok, I think I've found all affected implementors (linked in the PRs above). The scope of the potential breakage is much more limited than it could have been. |
I think my project face issue related to this change:
Any idea how to fix it ? |
The problem with a transformer having a less specific type than the stream it is transforming can be fixed by changing This way, the fact that a stream can be transformed by a transformer with a more general type (violating the substitution principle) is changed to the fact that a transformer can transform a stream of a more specific type (the normal behavior for parameters and expressions). |
Yeah I know that you had to change it, but how I can fix my dependencies now?
…Sent from my iPhone
On 26/07/2019, at 9:40 PM, William Hesse ***@***.***> wrote:
The problem with a transformer having a less specific type than the stream it is transforming can be fixed by changing
res.transform(utf8.decoder)
to the equivalent call
utf8.decoder.bind(res)
This way, the fact that a stream can be transformed by a transformer with a more general type (violating the substitution principle) is changed to the fact that a transformer can transform a stream of a more specific type (the normal behavior for parameters and expressions).
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@rdev-software this has already been fixed in dependency_overrides:
servicestack:
git:
url: git://github.com/ServiceStack/servicestack-dart
ref: d0f26ff319271b971612268951a75158dcf6641e |
@rdev-software I asked the owner of |
* Prepare for HttpClientResponse Uint8List SDK change An upcoming change in the Dart SDK will change `HttpClientResponse` from implementing `Stream<List<int>>` to instead implement `Stream<Uint8List>`. This forwards-compatible change to `_MockHttpClientResponse` is being made to allow for a smooth rollout of that SDK breaking change. The current structure of the class is as follows: ```dart _MockHttpClientResponse extends Stream<List<int>> implements HttpClientResponse { ... } ``` This structure would require that the Dart SDK change land atomically a change to the class (`extends Stream<Uint8List>`). This atomic landing requirement doesn't play well at all with Flutter's roll model vis-a-vis the Dart SDK's roll model to Google's internal repo. As such, this commit changes the structure of `_MockHttpClientResponse` to be: ```dart _MockHttpClientResponse implements HttpClientResponse { final Stream<Uint8List> _delegate; ... } ``` Once the Dart SDK change has fully rolled out, we can simplify this class back to its former structure. dart-lang/sdk#36900 * Review comment
Follow-on change to flutter#34863 (see that change for context), whereby we ensure that we're properly dealing in `Uint8List`. These necessary changes would have been caught by disabling implicit casts in our analysis options. dart-lang/sdk#36900 flutter#13815
An upcoming change in the Dart SDK changes `Socket` from implementing `Stream<List<int>>` to implementing `Stream<Uint8List>`. This forwards-compatible change in flutter_tools prepares for that Dart SDK change. dart-lang/sdk#36900
What is the current status of this? Did any of this end up landing? cc @aadilmaan |
The original proposal landed and is in Dart 2.5.0. The expanded proposal was mostly backed out - specifically, the https://github.com/dart-lang/sdk/blob/master/CHANGELOG.md#core-libraries-1 |
Closing |
This updates call sites with forward-compatible fixes for a recent Dart SDK change that changed the following APIs to be `Stream<Uint8List>` rather than `Stream<List<int>>`: * HttpClientResponse * File.openRead() dart-lang/sdk#36900
A recent change to the Dart SDK updated `HttpClientResponse` to implement `Stream<Uint8List>` rather than implementing `Stream<List<int>>`. This forwards-compatible chnage updates calls to `Stream.transform(StreamTransformer)` to instead call the functionally equivalent `StreamTransformer.bind(Stream)` API, which puts the stream in a covariant position and thus causes the SDK change to be non-breaking. dart-lang/sdk#36900
…t-lang/file#123) This is in preparation for dart-lang/sdk#36900
An upcoming change to the Dart SDK will change the signature of `File.openRead()` from returning `Stream<List<int>>` to returning `Stream<Uint8List>`. This forwards-compatible change prepares for that SDK breaking change by casting the Stream to `List<int>` before transforming it. dart-lang/sdk#36900
…rt-archive/http2#44) An upcoming change to the Dart SDK will change `HttpRequest` and `HttpClientResponse` from implementing `Stream<List<int>>` to implementing `Stream<Uint8List>`. This forwards-compatible change prepares for that SDK breaking change by casting the Stream to `List<int>` before transforming it. dart-lang/sdk#36900
* Make Stdin act like a Stream<Uint8List> In preparation for dart-lang/sdk#36900 * Bump version, and add changelog entry
Current state
The following methods all return
Uint8List
, yet they are only declared to returnList<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 asthe source list, yet they only declare that they return the more generic type (e.g.
List<int>
,List<float>
, orList<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 thanList<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
:Uint8List
(such as defensively wrapping the result in aUint8List
), which causes unnecessary overhead.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.To match the documentation
Utf8Encoder
andBase64Decoder.convert
, for instance, already document that they returnUint8List
.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
andpackage: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.
The text was updated successfully, but these errors were encountered: