Skip to content

Commit

Permalink
Improve documentation of compute() function (#116878)
Browse files Browse the repository at this point in the history
This improves the documentation of the `compute()` function as follows:

  * Instead of making `compute` a top-level constant, we make it a
    function. This allows the generated API docs to show a function
    signature with parameters and their names, making it *much* clearer
    to users what function is being documented.

  * We mention that on web-backends this is running `compute()` on the
    normal eventloop whereas on on native platforms it runs in a
    separate isolate.

  * We mention that callback, message and result have to be sendable
    across isolates. We also mention that they may be copied.

  * We link to both `Isolate.run` & `SendPort.send` for more information.

  * We use `M` for the type of `message` instead the rather confusing
    `Q`.
  • Loading branch information
mkustermann committed Dec 15, 2022
1 parent dcd2170 commit fc3571e
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 46 deletions.
3 changes: 2 additions & 1 deletion packages/flutter/lib/src/foundation/_isolates_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import 'isolates.dart' as isolates;
export 'isolates.dart' show ComputeCallback;

/// The dart:io implementation of [isolate.compute].
Future<R> compute<Q, R>(isolates.ComputeCallback<Q, R> callback, Q message, {String? debugLabel}) async {
@pragma('vm:prefer-inline')
Future<R> compute<M, R>(isolates.ComputeCallback<M, R> callback, M message, {String? debugLabel}) async {
debugLabel ??= kReleaseMode ? 'compute' : callback.toString();

return Isolate.run<R>(() {
Expand Down
3 changes: 2 additions & 1 deletion packages/flutter/lib/src/foundation/_isolates_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import 'isolates.dart' as isolates;
export 'isolates.dart' show ComputeCallback;

/// The dart:html implementation of [isolate.compute].
Future<R> compute<Q, R>(isolates.ComputeCallback<Q, R> callback, Q message, { String? debugLabel }) async {
@pragma('dart2js:tryInline')
Future<R> compute<M, R>(isolates.ComputeCallback<M, R> callback, M message, { String? debugLabel }) async {
// To avoid blocking the UI immediately for an expensive function call, we
// pump a single frame to allow the framework to complete the current set
// of work.
Expand Down
64 changes: 20 additions & 44 deletions packages/flutter/lib/src/foundation/isolates.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,17 @@ import '_isolates_io.dart'

/// Signature for the callback passed to [compute].
///
/// {@macro flutter.foundation.compute.types}
///
/// Instances of [ComputeCallback] must be functions that can be sent to an
/// isolate.
/// {@macro flutter.foundation.compute.callback}
///
/// {@macro flutter.foundation.compute.types}
typedef ComputeCallback<Q, R> = FutureOr<R> Function(Q message);
typedef ComputeCallback<M, R> = FutureOr<R> Function(M message);

/// The signature of [compute], which spawns an isolate, runs `callback` on
/// that isolate, passes it `message`, and (eventually) returns the value
/// returned by `callback`.
///
/// {@macro flutter.foundation.compute.usecase}
///
/// The function used as `callback` must be one that can be sent to an isolate.
/// {@macro flutter.foundation.compute.callback}
///
/// {@macro flutter.foundation.compute.types}
///
/// The `debugLabel` argument can be specified to provide a name to add to the
/// [Timeline]. This is useful when profiling an application.
typedef ComputeImpl = Future<R> Function<Q, R>(ComputeCallback<Q, R> callback, Q message, { String? debugLabel });
typedef ComputeImpl = Future<R> Function<M, R>(ComputeCallback<M, R> callback, M message, { String? debugLabel });

/// A function that spawns an isolate and runs the provided `callback` on that
/// isolate, passes it the provided `message`, and (eventually) returns the
/// value returned by `callback`.
/// Asynchronously runs the given [callback] - with the provided [message] -
/// in the background and completes with the result.
///
/// {@template flutter.foundation.compute.usecase}
/// This is useful for operations that take longer than a few milliseconds, and
Expand Down Expand Up @@ -68,34 +52,26 @@ typedef ComputeImpl = Future<R> Function<Q, R>(ComputeCallback<Q, R> callback, Q
/// ```
/// {@end-tool}
///
/// The function used as `callback` must be one that can be sent to an isolate.
/// {@template flutter.foundation.compute.callback}
/// Qualifying functions include:
///
/// * top-level functions
/// * static methods
/// * closures that only capture objects that can be sent to an isolate
/// On web platforms this will run [callback] on the current eventloop.
/// On native platforms this will run [callback] in a separate isolate.
///
/// Using closures must be done with care. Due to
/// [dart-lang/sdk#36983](https://github.com/dart-lang/sdk/issues/36983) a
/// closure may capture objects that, while not directly used in the closure
/// itself, may prevent it from being sent to an isolate.
/// {@endtemplate}
///
/// {@template flutter.foundation.compute.types}
/// The [compute] method accepts the following parameters:
/// {@template flutter.foundation.compute.callback}
///
/// * `Q` is the type of the message that kicks off the computation.
/// * `R` is the type of the value returned.
/// The `callback`, the `message` given to it as well as the result have to be
/// objects that can be sent across isolates (as they may be transitively copied
/// if needed). The majority of objects can be sent across isolates.
///
/// There are limitations on the values that can be sent and received to and
/// from isolates. These limitations constrain the values of `Q` and `R` that
/// are possible. See the discussion at [SendPort.send].
/// See [SendPort.send] for more information about exceptions as well as a note
/// of warning about sending closures, which can capture more state than needed.
///
/// The same limitations apply to any errors generated by the computation.
/// {@endtemplate}
///
/// See also:
/// On native platforms `await compute(fun, message)` is equivalent to
/// `await Isolate.run(() => fun(message))`. See also [Isolate.run].
///
/// * [ComputeImpl], for the [compute] function's signature.
const ComputeImpl compute = isolates.compute;
/// The `debugLabel` - if provided - is used as name for the isolate that
/// executes `callback`. [Timeline] events produced by that isolate will have
/// the name associated with them. This is useful when profiling an application.
Future<R> compute<M, R>(ComputeCallback<M, R> callback, M message, {String? debugLabel}) {
return isolates.compute<M, R>(callback, message, debugLabel: debugLabel);
}

0 comments on commit fc3571e

Please sign in to comment.